This is an automated email from the ASF dual-hosted git repository.

fokko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new bb5ea69  feat: Add lookup tables to StructType (#12)
bb5ea69 is described below

commit bb5ea69d4c84a657b742e11db6397a6af5dcb0fe
Author: JanKaul <[email protected]>
AuthorDate: Fri Jul 28 13:36:01 2023 +0200

    feat: Add lookup tables to StructType (#12)
    
    * add id_lookup to structtype
    
    * add name lookup for structtype
    
    * fix clippy warnings
    
    * refactor lookup creation into structtype constructor
    
    * add comment to constructor
    
    * Remove name lookup
    
    * Remove name lookup from tests
    
    * Fix rust fmt
    
    * Fix rust fmt
    
    * Rename field_by_id
---
 src/spec/datatypes.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 9 deletions(-)

diff --git a/src/spec/datatypes.rs b/src/spec/datatypes.rs
index 3005b27..6825442 100644
--- a/src/spec/datatypes.rs
+++ b/src/spec/datatypes.rs
@@ -18,10 +18,10 @@
 /*!
  * Data Types
 */
-use std::{fmt, ops::Index};
+use std::{collections::BTreeMap, fmt, ops::Index};
 
 use serde::{
-    de::{Error, IntoDeserializer},
+    de::{self, Error, IntoDeserializer, MapAccess, Visitor},
     Deserialize, Deserializer, Serialize, Serializer,
 };
 
@@ -190,21 +190,74 @@ impl fmt::Display for PrimitiveType {
 }
 
 /// DataType for a specific struct
-#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
+#[derive(Debug, Serialize, PartialEq, Eq, Clone)]
 #[serde(rename = "struct", tag = "type")]
 pub struct StructType {
     /// Struct fields
     fields: Vec<StructField>,
+    /// Lookup for index by field id
+    #[serde(skip_serializing)]
+    id_lookup: BTreeMap<i32, usize>,
+}
+
+impl<'de> Deserialize<'de> for StructType {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        #[serde(field_identifier, rename_all = "lowercase")]
+        enum Field {
+            Type,
+            Fields,
+        }
+
+        struct StructTypeVisitor;
+
+        impl<'de> Visitor<'de> for StructTypeVisitor {
+            type Value = StructType;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result 
{
+                formatter.write_str("struct")
+            }
+
+            fn visit_map<V>(self, mut map: V) -> Result<StructType, V::Error>
+            where
+                V: MapAccess<'de>,
+            {
+                let mut fields = None;
+                while let Some(key) = map.next_key()? {
+                    match key {
+                        Field::Type => (),
+                        Field::Fields => {
+                            if fields.is_some() {
+                                return 
Err(de::Error::duplicate_field("fields"));
+                            }
+                            fields = Some(map.next_value()?);
+                        }
+                    }
+                }
+                let fields: Vec<StructField> =
+                    fields.ok_or_else(|| de::Error::missing_field("fields"))?;
+
+                Ok(StructType::new(fields))
+            }
+        }
+
+        const FIELDS: &[&str] = &["type", "fields"];
+        deserializer.deserialize_struct("struct", FIELDS, StructTypeVisitor)
+    }
 }
 
 impl StructType {
-    /// Get structfield with certain id
-    pub fn get(&self, id: usize) -> Option<&StructField> {
-        self.fields.iter().find(|field| field.id as usize == id)
+    /// Creates a struct type with the given fields.
+    pub fn new(fields: Vec<StructField>) -> Self {
+        let id_lookup = BTreeMap::from_iter(fields.iter().enumerate().map(|(i, 
x)| (x.id, i)));
+        Self { fields, id_lookup }
     }
-    /// Get structfield with certain name
-    pub fn get_name(&self, name: &str) -> Option<&StructField> {
-        self.fields.iter().find(|field| field.name == name)
+    /// Get structfield with certain id
+    pub fn field_by_id(&self, id: i32) -> Option<&StructField> {
+        self.fields.get(*self.id_lookup.get(&id)?)
     }
 }
 
@@ -349,6 +402,7 @@ mod tests {
                     initial_default: None,
                     write_default: None,
                 }],
+                id_lookup: BTreeMap::from([(1, 0)]),
             }),
         )
     }
@@ -381,6 +435,7 @@ mod tests {
                     initial_default: None,
                     write_default: None,
                 }],
+                id_lookup: BTreeMap::from([(1, 0)]),
             }),
         )
     }
@@ -431,6 +486,7 @@ mod tests {
                         write_default: None,
                     },
                 ],
+                id_lookup: BTreeMap::from([(1, 0), (2, 1)]),
             }),
         )
     }

Reply via email to