This is an automated email from the ASF dual-hosted git repository. kriskras99 pushed a commit to branch feat/namespace_for_named_types in repository https://gitbox.apache.org/repos/asf/avro-rs.git
commit 6f2a27b638ac2a5fc1b1416db34d8c442ac49e14 Author: Kriskras99 <[email protected]> AuthorDate: Thu Apr 9 08:32:20 2026 +0200 wip: Namespace for named types defined by this library --- avro/src/schema/name.rs | 6 ++++++ avro/src/schema/union.rs | 27 +++++++++++++++++++++++++ avro/src/serde/derive.rs | 41 ++++++++++++++------------------------ avro/src/serde/deser_schema/mod.rs | 27 +++++++++++++++++++------ avro/src/serde/ser_schema/mod.rs | 27 +++++++++++++++++++------ avro/src/serde/ser_schema/union.rs | 15 +++++++++++--- avro_derive/tests/derive.rs | 10 +++++++--- 7 files changed, 109 insertions(+), 44 deletions(-) diff --git a/avro/src/schema/name.rs b/avro/src/schema/name.rs index 31a5f1e..c03e58b 100644 --- a/avro/src/schema/name.rs +++ b/avro/src/schema/name.rs @@ -230,6 +230,12 @@ impl Debug for Name { } } +impl AsRef<str> for Name { + fn as_ref(&self) -> &str { + self.namespace_and_name.as_ref() + } +} + impl Display for Name { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { assert!( diff --git a/avro/src/schema/union.rs b/avro/src/schema/union.rs index 9a2a1f3..1561c11 100644 --- a/avro/src/schema/union.rs +++ b/avro/src/schema/union.rs @@ -128,6 +128,33 @@ impl UnionSchema { Ok(None) } + /// Get the index and schema for the provided Rust type name. + /// + /// Will use `names` to resolve references. + pub(crate) fn find_fully_qualified_named_schema<'s>( + &'s self, + full_name: &str, + names: &'s HashMap<Name, impl Borrow<Schema>>, + ) -> Result<Option<(usize, &'s Schema)>, Error> { + for index in self.named_index.iter().copied() { + let schema = &self.schemas[index]; + if let Some(schema_name) = schema.name() + && schema_name.as_ref() == full_name + { + let schema = if let Schema::Ref { name } = schema { + names + .get(name) + .ok_or_else(|| Details::SchemaResolutionError(name.clone()))? + .borrow() + } else { + schema + }; + return Ok(Some((index, schema))); + } + } + Ok(None) + } + /// Find a [`Schema::Fixed`] with the given size. /// /// Will use `names` to resolve references. diff --git a/avro/src/serde/derive.rs b/avro/src/serde/derive.rs index 573b6b3..8c722cf 100644 --- a/avro/src/serde/derive.rs +++ b/avro/src/serde/derive.rs @@ -613,17 +613,16 @@ where } impl AvroSchemaComponent for core::time::Duration { - /// The schema is [`Schema::Record`] with the name `Duration`. + /// The schema is [`Schema::Record`] with the name `org.apache.avro.rust.Duration`. /// /// It has two fields: - /// - `secs` with the schema `Schema::Fixed(name: "u64", size: 8)` + /// - `secs` with the schema `Schema::Fixed(name: "org.apache.avro.rust.u64", size: 8)` /// - `nanos` with the schema `Schema::Long` fn get_schema_in_ctxt( named_schemas: &mut HashSet<Name>, enclosing_namespace: NamespaceRef, ) -> Schema { - let name = Name::new_with_enclosing_namespace("Duration", enclosing_namespace) - .expect("Name is valid"); + let name = Name::new("org.apache.avro.rust.Duration").expect("Name is valid"); if named_schemas.contains(&name) { Schema::Ref { name } } else { @@ -657,17 +656,13 @@ impl AvroSchemaComponent for core::time::Duration { } impl AvroSchemaComponent for uuid::Uuid { - /// The schema is [`Schema::Uuid`] with the name `uuid`. + /// The schema is [`Schema::Uuid`] with the name `org.apache.avro.rust.Uuid`. /// /// The underlying schema is [`Schema::Fixed`] with a size of 16. /// /// If you're using `human_readable: true` you need to override this schema with a `Schema::String`. - fn get_schema_in_ctxt( - named_schemas: &mut HashSet<Name>, - enclosing_namespace: NamespaceRef, - ) -> Schema { - let name = - Name::new_with_enclosing_namespace("uuid", enclosing_namespace).expect("Name is valid"); + fn get_schema_in_ctxt(named_schemas: &mut HashSet<Name>, _: NamespaceRef) -> Schema { + let name = Name::new("org.apache.avro.rust.Uuid").expect("Name is valid"); if named_schemas.contains(&name) { Schema::Ref { name } } else { @@ -692,13 +687,9 @@ impl AvroSchemaComponent for uuid::Uuid { } impl AvroSchemaComponent for u64 { - /// The schema is [`Schema::Fixed`] of size 8 with the name `u64`. - fn get_schema_in_ctxt( - named_schemas: &mut HashSet<Name>, - enclosing_namespace: NamespaceRef, - ) -> Schema { - let name = - Name::new_with_enclosing_namespace("u64", enclosing_namespace).expect("Name is valid"); + /// The schema is [`Schema::Fixed`] of size 8 with the name `org.apache.avro.rust.u64`. + fn get_schema_in_ctxt(named_schemas: &mut HashSet<Name>, _: NamespaceRef) -> Schema { + let name = Name::new("org.apache.avro.rust.u64").expect("Name is valid"); if named_schemas.contains(&name) { Schema::Ref { name } } else { @@ -723,13 +714,12 @@ impl AvroSchemaComponent for u64 { } impl AvroSchemaComponent for u128 { - /// The schema is [`Schema::Fixed`] of size 16 with the name `u128`. + /// The schema is [`Schema::Fixed`] of size 16 with the name `org.apache.avro.rust.u128`. fn get_schema_in_ctxt( named_schemas: &mut HashSet<Name>, - enclosing_namespace: NamespaceRef, + _: NamespaceRef, ) -> Schema { - let name = - Name::new_with_enclosing_namespace("u128", enclosing_namespace).expect("Name is valid"); + let name = Name::new("org.apache.avro.rust.u128").expect("Name is valid"); if named_schemas.contains(&name) { Schema::Ref { name } } else { @@ -754,13 +744,12 @@ impl AvroSchemaComponent for u128 { } impl AvroSchemaComponent for i128 { - /// The schema is [`Schema::Fixed`] of size 16 with the name `i128`. + /// The schema is [`Schema::Fixed`] of size 16 with the name `org.apache.avro.rust.i128`. fn get_schema_in_ctxt( named_schemas: &mut HashSet<Name>, - enclosing_namespace: NamespaceRef, + _: NamespaceRef, ) -> Schema { - let name = - Name::new_with_enclosing_namespace("i128", enclosing_namespace).expect("Name is valid"); + let name = Name::new("org.apache.avro.rust.i128").expect("Name is valid"); if named_schemas.contains(&name) { Schema::Ref { name } } else { diff --git a/avro/src/serde/deser_schema/mod.rs b/avro/src/serde/deser_schema/mod.rs index ba8590c..0ece35b 100644 --- a/avro/src/serde/deser_schema/mod.rs +++ b/avro/src/serde/deser_schema/mod.rs @@ -348,11 +348,16 @@ impl<'de, 's, 'r, R: Read, S: Borrow<Schema>> Deserializer<'de> V: Visitor<'de>, { match self.schema { - Schema::Fixed(fixed) if fixed.size == 16 && fixed.name.name() == "i128" => { + Schema::Fixed(fixed) + if fixed.size == 16 && fixed.name.as_ref() == "org.apache.avro.rust.i128" => + { visitor.visit_i128(i128::from_le_bytes(self.read_array()?)) } Schema::Union(union) => self.with_union(union)?.deserialize_i128(visitor), - _ => Err(self.error("i128", r#"Expected Schema::Fixed(name: "i128", size: 16)"#)), + _ => Err(self.error( + "i128", + r#"Expected Schema::Fixed(name: "org.apache.avro.rust.i128", size: 16)"#, + )), } } @@ -405,11 +410,16 @@ impl<'de, 's, 'r, R: Read, S: Borrow<Schema>> Deserializer<'de> V: Visitor<'de>, { match self.schema { - Schema::Fixed(fixed) if fixed.size == 8 && fixed.name.name() == "u64" => { + Schema::Fixed(fixed) + if fixed.size == 8 && fixed.name.as_ref() == "org.apache.avro.rust.u64" => + { visitor.visit_u64(u64::from_le_bytes(self.read_array()?)) } Schema::Union(union) => self.with_union(union)?.deserialize_u64(visitor), - _ => Err(self.error("u64", r#"Expected Schema::Fixed(name: "u64", size: 8)"#)), + _ => Err(self.error( + "u64", + r#"Expected Schema::Fixed(name: "org.apache.avro.rust.u64", size: 8)"#, + )), } } @@ -418,11 +428,16 @@ impl<'de, 's, 'r, R: Read, S: Borrow<Schema>> Deserializer<'de> V: Visitor<'de>, { match self.schema { - Schema::Fixed(fixed) if fixed.size == 16 && fixed.name.name() == "u128" => { + Schema::Fixed(fixed) + if fixed.size == 16 && fixed.name.as_ref() == "org.apache.avro.rust.u128" => + { visitor.visit_u128(u128::from_le_bytes(self.read_array()?)) } Schema::Union(union) => self.with_union(union)?.deserialize_u128(visitor), - _ => Err(self.error("u128", r#"Expected Schema::Fixed(name: "u128", size: 16)"#)), + _ => Err(self.error( + "u128", + r#"Expected Schema::Fixed(name: "org.apache.avro.rust.u128", size: 16)"#, + )), } } diff --git a/avro/src/serde/ser_schema/mod.rs b/avro/src/serde/ser_schema/mod.rs index d6975e2..b4daf3a 100644 --- a/avro/src/serde/ser_schema/mod.rs +++ b/avro/src/serde/ser_schema/mod.rs @@ -249,13 +249,18 @@ impl<'s, 'w, W: Write, S: Borrow<Schema>> Serializer for SchemaAwareSerializer<' fn serialize_i128(mut self, v: i128) -> Result<Self::Ok, Self::Error> { match self.schema { - Schema::Fixed(fixed) if fixed.size == 16 && fixed.name.name() == "i128" => { + Schema::Fixed(fixed) + if fixed.size == 16 && fixed.name.as_ref() == "org.apache.avro.rust.i128" => + { self.write_array(v.to_le_bytes()) } Schema::Union(union) => { UnionSerializer::new(self.writer, union, self.config).serialize_i128(v) } - _ => Err(self.error("i128", r#"Expected Schema::Fixed(name: "i128", size: 16)"#)), + _ => Err(self.error( + "i128", + r#"Expected Schema::Fixed(name: "org.apache.avro.rust.i128", size: 16)"#, + )), } } @@ -273,25 +278,35 @@ impl<'s, 'w, W: Write, S: Borrow<Schema>> Serializer for SchemaAwareSerializer<' fn serialize_u64(mut self, v: u64) -> Result<Self::Ok, Self::Error> { match self.schema { - Schema::Fixed(fixed) if fixed.size == 8 && fixed.name.name() == "u64" => { + Schema::Fixed(fixed) + if fixed.size == 8 && fixed.name.as_ref() == "org.apache.avro.rust.u64" => + { self.write_array(v.to_le_bytes()) } Schema::Union(union) => { UnionSerializer::new(self.writer, union, self.config).serialize_u64(v) } - _ => Err(self.error("u64", r#"Expected Schema::Fixed(name: "u64", size: 8)"#)), + _ => Err(self.error( + "u64", + r#"Expected Schema::Fixed(name: "org.apache.avro.rust.u64", size: 8)"#, + )), } } fn serialize_u128(mut self, v: u128) -> Result<Self::Ok, Self::Error> { match self.schema { - Schema::Fixed(fixed) if fixed.size == 16 && fixed.name.name() == "u128" => { + Schema::Fixed(fixed) + if fixed.size == 16 && fixed.name.as_ref() == "org.apache.avro.rust.u128" => + { self.write_array(v.to_le_bytes()) } Schema::Union(union) => { UnionSerializer::new(self.writer, union, self.config).serialize_u128(v) } - _ => Err(self.error("u128", r#"Expected Schema::Fixed(name: "u128", size: 16)"#)), + _ => Err(self.error( + "u128", + r#"Expected Schema::Fixed(name: "org.apache.avro.rust.u128", size: 16)"#, + )), } } diff --git a/avro/src/serde/ser_schema/union.rs b/avro/src/serde/ser_schema/union.rs index d1aa73e..8b5d468 100644 --- a/avro/src/serde/ser_schema/union.rs +++ b/avro/src/serde/ser_schema/union.rs @@ -166,7 +166,10 @@ impl<'s, 'w, W: Write, S: Borrow<Schema>> Serializer for UnionSerializer<'s, 'w, } fn serialize_i128(mut self, v: i128) -> Result<Self::Ok, Self::Error> { - match self.union.find_named_schema("i128", self.config.names)? { + match self + .union + .find_fully_qualified_named_schema("org.apache.avro.rust.i128", self.config.names)? + { Some((index, Schema::Fixed(FixedSchema { size: 16, .. }))) => { let mut bytes_written = zig_i32(index as i32, &mut *self.writer)?; bytes_written += self.write_array(v.to_le_bytes())?; @@ -192,7 +195,10 @@ impl<'s, 'w, W: Write, S: Borrow<Schema>> Serializer for UnionSerializer<'s, 'w, } fn serialize_u64(mut self, v: u64) -> Result<Self::Ok, Self::Error> { - match self.union.find_named_schema("u64", self.config.names)? { + match self + .union + .find_fully_qualified_named_schema("org.apache.avro.rust.u64", self.config.names)? + { Some((index, Schema::Fixed(FixedSchema { size: 8, .. }))) => { let mut bytes_written = zig_i32(index as i32, &mut *self.writer)?; bytes_written += self.write_array(v.to_le_bytes())?; @@ -206,7 +212,10 @@ impl<'s, 'w, W: Write, S: Borrow<Schema>> Serializer for UnionSerializer<'s, 'w, } fn serialize_u128(mut self, v: u128) -> Result<Self::Ok, Self::Error> { - match self.union.find_named_schema("u128", self.config.names)? { + match self + .union + .find_fully_qualified_named_schema("org.apache.avro.rust.u128", self.config.names)? + { Some((index, Schema::Fixed(FixedSchema { size: 16, .. }))) => { let mut bytes_written = zig_i32(index as i32, &mut *self.writer)?; bytes_written += self.write_array(v.to_le_bytes())?; diff --git a/avro_derive/tests/derive.rs b/avro_derive/tests/derive.rs index 42835db..e2509c3 100644 --- a/avro_derive/tests/derive.rs +++ b/avro_derive/tests/derive.rs @@ -1954,7 +1954,8 @@ fn avro_rs_397_uuid() { "type":{ "type":"fixed", "logicalType":"uuid", - "name":"uuid", + "name":"Uuid", + "namespace": "org.apache.avro.rust", "default":"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", "size":16 } @@ -2140,6 +2141,7 @@ fn avro_rs_414_round_trip_char_u64_u128_i128() { "name": "b", "type": { "name": "u64", + "namespace": "org.apache.avro.rust", "type": "fixed", "size": 8 } @@ -2148,6 +2150,7 @@ fn avro_rs_414_round_trip_char_u64_u128_i128() { "name": "c", "type": { "name": "u128", + "namespace": "org.apache.avro.rust", "type": "fixed", "size": 16 } @@ -2156,6 +2159,7 @@ fn avro_rs_414_round_trip_char_u64_u128_i128() { "name": "d", "type": { "name": "i128", + "namespace": "org.apache.avro.rust", "type": "fixed", "size": 16 } @@ -2420,7 +2424,7 @@ fn avro_rs_476_field_default() { let schema = Foo::get_schema(); assert_eq!( serde_json::to_string(&schema).unwrap(), - r#"{"type":"record","name":"Foo","fields":[{"name":"_a","type":"boolean"},{"name":"_b","type":"int"},{"name":"_c","type":"int"},{"name":"_d","type":"int"},{"name":"_e","type":"long"},{"name":"_f","type":"int"},{"name":"_g","type":"int"},{"name":"_h","type":"long"},{"name":"_i","type":"float"},{"name":"_j","type":"double"},{"name":"_k","type":"string"},{"name":"_l","type":"string"},{"name":"_m","type":"string"},{"name":"_n","type":{"type":"record","name":"Spam","fields":[{"name":" [...] + r#"{"type":"record","name":"Foo","fields":[{"name":"_a","type":"boolean"},{"name":"_b","type":"int"},{"name":"_c","type":"int"},{"name":"_d","type":"int"},{"name":"_e","type":"long"},{"name":"_f","type":"int"},{"name":"_g","type":"int"},{"name":"_h","type":"long"},{"name":"_i","type":"float"},{"name":"_j","type":"double"},{"name":"_k","type":"string"},{"name":"_l","type":"string"},{"name":"_m","type":"string"},{"name":"_n","type":{"type":"record","name":"Spam","fields":[{"name":" [...] ); } @@ -2531,7 +2535,7 @@ fn avro_rs_476_field_default_provided() { let schema = Foo::get_schema(); assert_eq!( serde_json::to_string(&schema).unwrap(), - r#"{"type":"record","name":"Foo","fields":[{"name":"_a","type":"boolean","default":true},{"name":"_b","type":"int","default":42},{"name":"_c","type":"int","default":42},{"name":"_d","type":"int","default":42},{"name":"_e","type":"long","default":42},{"name":"_f","type":"int","default":42},{"name":"_g","type":"int","default":42},{"name":"_h","type":"long","default":42},{"name":"_i","type":"float","default":42.0},{"name":"_j","type":"double","default":42.0},{"name":"_k","type":"str [...] + r#"{"type":"record","name":"Foo","fields":[{"name":"_a","type":"boolean","default":true},{"name":"_b","type":"int","default":42},{"name":"_c","type":"int","default":42},{"name":"_d","type":"int","default":42},{"name":"_e","type":"long","default":42},{"name":"_f","type":"int","default":42},{"name":"_g","type":"int","default":42},{"name":"_h","type":"long","default":42},{"name":"_i","type":"float","default":42.0},{"name":"_j","type":"double","default":42.0},{"name":"_k","type":"str [...] ); }
