This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 4a65d5d feat: Accept more inputs for `Schema::parse_(str_with)_list`
(#195)
4a65d5d is described below
commit 4a65d5da5d3564045bd8c03cb62f210aa1100667
Author: Kriskras99 <[email protected]>
AuthorDate: Thu May 15 07:57:04 2025 +0200
feat: Accept more inputs for `Schema::parse_(str_with)_list` (#195)
They now accept anything that can iterate over types that can be
converted into strings. For example: `Vec<String>`, `&[&str]`, and
`files.iter().map(std::fs::read_to_string).filter_map(Result::ok)`.
---
avro/src/schema.rs | 38 ++++++++++++++++++-------------
avro/src/schema_compatibility.rs | 2 +-
avro/src/types.rs | 4 ++--
avro/tests/schema.rs | 28 +++++++++++------------
avro/tests/to_from_avro_datum_schemata.rs | 6 ++---
avro/tests/union_schema.rs | 10 ++++----
6 files changed, 47 insertions(+), 41 deletions(-)
diff --git a/avro/src/schema.rs b/avro/src/schema.rs
index c12bc93..ee88e2b 100644
--- a/avro/src/schema.rs
+++ b/avro/src/schema.rs
@@ -1096,11 +1096,14 @@ impl Schema {
/// during parsing.
///
/// If two of the input schemas have the same fullname, an Error will be
returned.
- pub fn parse_list(input: &[&str]) -> AvroResult<Vec<Schema>> {
- let mut input_schemas: HashMap<Name, Value> =
HashMap::with_capacity(input.len());
- let mut input_order: Vec<Name> = Vec::with_capacity(input.len());
- for js in input {
- let schema: Value =
serde_json::from_str(js).map_err(Error::ParseSchemaJson)?;
+ pub fn parse_list(input: impl IntoIterator<Item = impl AsRef<str>>) ->
AvroResult<Vec<Schema>> {
+ let input = input.into_iter();
+ let input_len = input.size_hint().0;
+ let mut input_schemas: HashMap<Name, Value> =
HashMap::with_capacity(input_len);
+ let mut input_order: Vec<Name> = Vec::with_capacity(input_len);
+ for json in input {
+ let json = json.as_ref();
+ let schema: Value =
serde_json::from_str(json).map_err(Error::ParseSchemaJson)?;
if let Value::Object(inner) = &schema {
let name = Name::parse(inner, &None)?;
let previous_value = input_schemas.insert(name.clone(),
schema);
@@ -1116,7 +1119,7 @@ impl Schema {
input_schemas,
resolving_schemas: HashMap::default(),
input_order,
- parsed_schemas: HashMap::with_capacity(input.len()),
+ parsed_schemas: HashMap::with_capacity(input_len),
};
parser.parse_list()
}
@@ -1135,11 +1138,14 @@ impl Schema {
/// * `schemata` - a slice of additional schemas that is used to resolve
cross-references
pub fn parse_str_with_list(
schema: &str,
- schemata: &[&str],
+ schemata: impl IntoIterator<Item = impl AsRef<str>>,
) -> AvroResult<(Schema, Vec<Schema>)> {
- let mut input_schemas: HashMap<Name, Value> =
HashMap::with_capacity(schemata.len());
- let mut input_order: Vec<Name> = Vec::with_capacity(schemata.len());
+ let schemata = schemata.into_iter();
+ let schemata_len = schemata.size_hint().0;
+ let mut input_schemas: HashMap<Name, Value> =
HashMap::with_capacity(schemata_len);
+ let mut input_order: Vec<Name> = Vec::with_capacity(schemata_len);
for json in schemata {
+ let json = json.as_ref();
let schema: Value =
serde_json::from_str(json).map_err(Error::ParseSchemaJson)?;
if let Value::Object(inner) = &schema {
let name = Name::parse(inner, &None)?;
@@ -1155,7 +1161,7 @@ impl Schema {
input_schemas,
resolving_schemas: HashMap::default(),
input_order,
- parsed_schemas: HashMap::with_capacity(schemata.len()),
+ parsed_schemas: HashMap::with_capacity(schemata_len),
};
parser.parse_input_schemas()?;
@@ -2782,7 +2788,7 @@ mod tests {
]
}"#;
- let schema_c = Schema::parse_list(&[schema_str_a, schema_str_b,
schema_str_c])?
+ let schema_c = Schema::parse_list([schema_str_a, schema_str_b,
schema_str_c])?
.last()
.unwrap()
.clone();
@@ -2831,7 +2837,7 @@ mod tests {
let schema_str_c = r#"["A", "B"]"#;
let (schema_c, schemata) =
- Schema::parse_str_with_list(schema_str_c, &[schema_str_a,
schema_str_b])?;
+ Schema::parse_str_with_list(schema_str_c, [schema_str_a,
schema_str_b])?;
let schema_a_expected = Schema::Record(RecordSchema {
name: Name::new("A")?,
@@ -2906,7 +2912,7 @@ mod tests {
let schema_str_c = r#"["A", "A"]"#;
- match Schema::parse_str_with_list(schema_str_c, &[schema_str_a1,
schema_str_a2]) {
+ match Schema::parse_str_with_list(schema_str_c, [schema_str_a1,
schema_str_a2]) {
Ok(_) => unreachable!("Expected an error that the name is already
defined"),
Err(e) => assert_eq!(
e.to_string(),
@@ -2937,7 +2943,7 @@ mod tests {
let schema_str_c = r#"["A", "A"]"#;
- match Schema::parse_str_with_list(schema_str_c, &[schema_str_a,
schema_str_b]) {
+ match Schema::parse_str_with_list(schema_str_c, [schema_str_a,
schema_str_b]) {
Ok(_) => unreachable!("Expected an error that schema_str_b is
missing a name field"),
Err(e) => assert_eq!(e.to_string(), "No `name` field"),
}
@@ -2960,7 +2966,7 @@ mod tests {
"fields": [ {"name": "field_one", "type": "A"} ]
}"#;
- let list = Schema::parse_list(&[schema_str_a, schema_str_b])?;
+ let list = Schema::parse_list([schema_str_a, schema_str_b])?;
let schema_a = list.first().unwrap().clone();
@@ -3000,7 +3006,7 @@ mod tests {
]
}"#;
- let schema_option_a = Schema::parse_list(&[schema_str_a,
schema_str_option_a])?
+ let schema_option_a = Schema::parse_list([schema_str_a,
schema_str_option_a])?
.last()
.unwrap()
.clone();
diff --git a/avro/src/schema_compatibility.rs b/avro/src/schema_compatibility.rs
index 5df7c52..909430d 100644
--- a/avro/src/schema_compatibility.rs
+++ b/avro/src/schema_compatibility.rs
@@ -1766,7 +1766,7 @@ mod tests {
"#,
];
- let schemas = Schema::parse_list(&schema_strs).unwrap();
+ let schemas = Schema::parse_list(schema_strs).unwrap();
SchemaCompatibility::can_read(&schemas[1], &schemas[1])?;
Ok(())
diff --git a/avro/src/types.rs b/avro/src/types.rs
index d5fa174..dd7dd77 100644
--- a/avro/src/types.rs
+++ b/avro/src/types.rs
@@ -2969,7 +2969,7 @@ Field with name '"b"' is not a member of the map items"#,
let avro_value = Value::from(value);
- let schemas = Schema::parse_list(&[main_schema, referenced_schema])?;
+ let schemas = Schema::parse_list([main_schema, referenced_schema])?;
let main_schema = schemas.first().unwrap();
let schemata: Vec<_> = schemas.iter().skip(1).collect();
@@ -3011,7 +3011,7 @@ Field with name '"b"' is not a member of the map items"#,
let avro_value = Value::from(value);
- let schemata = Schema::parse_list(&[referenced_enum,
referenced_record, main_schema])?;
+ let schemata = Schema::parse_list([referenced_enum, referenced_record,
main_schema])?;
let main_schema = schemata.last().unwrap();
let other_schemata: Vec<&Schema> = schemata.iter().take(2).collect();
diff --git a/avro/tests/schema.rs b/avro/tests/schema.rs
index c4a06c6..73967bb 100644
--- a/avro/tests/schema.rs
+++ b/avro/tests/schema.rs
@@ -187,7 +187,7 @@ fn test_parse_list_without_cross_deps() -> TestResult {
"size": 16
}"#;
let schema_strs = [schema_str_1, schema_str_2];
- let schemas = Schema::parse_list(&schema_strs)?;
+ let schemas = Schema::parse_list(schema_strs)?;
for schema_str in &schema_strs {
let parsed = Schema::parse_str(schema_str)?;
@@ -220,8 +220,8 @@ fn test_parse_list_with_cross_deps_basic() -> TestResult {
let schema_strs_first = [schema_a_str, schema_b_str];
let schema_strs_second = [schema_b_str, schema_a_str];
- let schemas_first = Schema::parse_list(&schema_strs_first)?;
- let schemas_second = Schema::parse_list(&schema_strs_second)?;
+ let schemas_first = Schema::parse_list(schema_strs_first)?;
+ let schemas_second = Schema::parse_list(schema_strs_second)?;
assert_eq!(schemas_first[0], schemas_second[1]);
assert_eq!(schemas_first[1], schemas_second[0]);
@@ -249,8 +249,8 @@ fn test_parse_list_recursive_type() -> TestResult {
}"#;
let schema_strs_first = [schema_str_1, schema_str_2];
let schema_strs_second = [schema_str_2, schema_str_1];
- let _ = Schema::parse_list(&schema_strs_first)?;
- let _ = Schema::parse_list(&schema_strs_second)?;
+ let _ = Schema::parse_list(schema_strs_first)?;
+ let _ = Schema::parse_list(schema_strs_second)?;
Ok(())
}
@@ -274,8 +274,8 @@ fn test_parse_list_with_cross_deps_and_namespaces() ->
TestResult {
]
}"#;
- let schemas_first = Schema::parse_list(&[schema_a_str, schema_b_str])?;
- let schemas_second = Schema::parse_list(&[schema_b_str, schema_a_str])?;
+ let schemas_first = Schema::parse_list([schema_a_str, schema_b_str])?;
+ let schemas_second = Schema::parse_list([schema_b_str, schema_a_str])?;
assert_eq!(schemas_first[0], schemas_second[1]);
assert_eq!(schemas_first[1], schemas_second[0]);
@@ -305,8 +305,8 @@ fn test_parse_list_with_cross_deps_and_namespaces_error()
-> TestResult {
let schema_strs_first = [schema_str_1, schema_str_2];
let schema_strs_second = [schema_str_2, schema_str_1];
- let _ = Schema::parse_list(&schema_strs_first).expect_err("Test failed");
- let _ = Schema::parse_list(&schema_strs_second).expect_err("Test failed");
+ let _ = Schema::parse_list(schema_strs_first).expect_err("Test failed");
+ let _ = Schema::parse_list(schema_strs_second).expect_err("Test failed");
Ok(())
}
@@ -453,7 +453,7 @@ fn test_parse_list_multiple_dependencies() -> TestResult {
]
}"#;
- let parsed = Schema::parse_list(&[schema_a_str, schema_b_str,
schema_c_str])?;
+ let parsed = Schema::parse_list([schema_a_str, schema_b_str,
schema_c_str])?;
let schema_strs = vec![schema_a_str, schema_b_str, schema_c_str];
for schema_str_perm in permutations(&schema_strs) {
let schema_str_perm: Vec<&str> = schema_str_perm.iter().map(|s|
**s).collect();
@@ -493,7 +493,7 @@ fn test_parse_list_shared_dependency() -> TestResult {
]
}"#;
- let parsed = Schema::parse_list(&[schema_a_str, schema_b_str,
schema_c_str])?;
+ let parsed = Schema::parse_list([schema_a_str, schema_b_str,
schema_c_str])?;
let schema_strs = vec![schema_a_str, schema_b_str, schema_c_str];
for schema_str_perm in permutations(&schema_strs) {
let schema_str_perm: Vec<&str> = schema_str_perm.iter().map(|s|
**s).collect();
@@ -526,7 +526,7 @@ fn test_name_collision_error() -> TestResult {
]
}"#;
- let _ = Schema::parse_list(&[schema_str_1, schema_str_2]).expect_err("Test
failed");
+ let _ = Schema::parse_list([schema_str_1, schema_str_2]).expect_err("Test
failed");
Ok(())
}
@@ -550,7 +550,7 @@ fn test_namespace_prevents_collisions() -> TestResult {
]
}"#;
- let parsed = Schema::parse_list(&[schema_str_1, schema_str_2])?;
+ let parsed = Schema::parse_list([schema_str_1, schema_str_2])?;
let parsed_1 = Schema::parse_str(schema_str_1)?;
let parsed_2 = Schema::parse_str(schema_str_2)?;
assert_eq!(parsed, vec!(parsed_1, parsed_2));
@@ -2346,7 +2346,7 @@ fn
avro_rs_66_test_independent_canonical_form_missing_ref() -> TestResult {
}"#;
let schema_strs = [record_primitive, record_usage];
- let schemata = Schema::parse_list(&schema_strs)?;
+ let schemata = Schema::parse_list(schema_strs)?;
assert!(matches!(
schemata[1].independent_canonical_form(&Vec::with_capacity(0)), //NOTE
- we're passing in an empty schemata
Err(Error::SchemaResolutionError(..))
diff --git a/avro/tests/to_from_avro_datum_schemata.rs
b/avro/tests/to_from_avro_datum_schemata.rs
index 776c446..6f2d595 100644
--- a/avro/tests/to_from_avro_datum_schemata.rs
+++ b/avro/tests/to_from_avro_datum_schemata.rs
@@ -46,7 +46,7 @@ fn test_avro_3683_multiple_schemata_to_from_avro_datum() ->
TestResult {
Value::Record(vec![(String::from("field_a"), Value::Float(1.0))]),
)]);
- let schemata: Vec<Schema> = Schema::parse_list(&[SCHEMA_A_STR,
SCHEMA_B_STR])?;
+ let schemata: Vec<Schema> = Schema::parse_list([SCHEMA_A_STR,
SCHEMA_B_STR])?;
let schemata: Vec<&Schema> = schemata.iter().collect();
// this is the Schema we want to use for write/read
@@ -70,7 +70,7 @@ fn
avro_rs_106_test_multiple_schemata_to_from_avro_datum_with_resolution() -> Te
Value::Record(vec![(String::from("field_a"), Value::Float(1.0))]),
)]);
- let schemata: Vec<Schema> = Schema::parse_list(&[SCHEMA_A_STR,
SCHEMA_B_STR])?;
+ let schemata: Vec<Schema> = Schema::parse_list([SCHEMA_A_STR,
SCHEMA_B_STR])?;
let schemata: Vec<&Schema> = schemata.iter().collect();
// this is the Schema we want to use for write/read
@@ -100,7 +100,7 @@ fn test_avro_3683_multiple_schemata_writer_reader() ->
TestResult {
Value::Record(vec![(String::from("field_a"), Value::Float(1.0))]),
)]);
- let schemata: Vec<Schema> = Schema::parse_list(&[SCHEMA_A_STR,
SCHEMA_B_STR])?;
+ let schemata: Vec<Schema> = Schema::parse_list([SCHEMA_A_STR,
SCHEMA_B_STR])?;
let schemata: Vec<&Schema> = schemata.iter().collect();
// this is the Schema we want to use for write/read
diff --git a/avro/tests/union_schema.rs b/avro/tests/union_schema.rs
index 6dcb1b6..106b062 100644
--- a/avro/tests/union_schema.rs
+++ b/avro/tests/union_schema.rs
@@ -82,7 +82,7 @@ where
#[test]
fn test_avro_3901_union_schema_round_trip_no_null() -> AvroResult<()> {
let schemata: Vec<Schema> =
- Schema::parse_list(&[SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_C_STR]).expect("parsing schemata");
+ Schema::parse_list([SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_C_STR]).expect("parsing schemata");
let input = C {
field_union: (UnionAB::A(A { field_a: 45.5 })),
@@ -126,7 +126,7 @@ struct D {
#[test]
fn test_avro_3901_union_schema_round_trip_null_at_start() -> AvroResult<()> {
let schemata: Vec<Schema> =
- Schema::parse_list(&[SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_D_STR]).expect("parsing schemata");
+ Schema::parse_list([SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_D_STR]).expect("parsing schemata");
let input = D {
field_union: UnionNoneAB::A(A { field_a: 54.25 }),
@@ -177,7 +177,7 @@ struct E {
#[test]
fn test_avro_3901_union_schema_round_trip_with_out_of_order_null() ->
AvroResult<()> {
let schemata: Vec<Schema> =
- Schema::parse_list(&[SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_E_STR]).expect("parsing schemata");
+ Schema::parse_list([SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_E_STR]).expect("parsing schemata");
let input = E {
field_union: UnionANoneB::A(A { field_a: 23.75 }),
@@ -228,7 +228,7 @@ struct F {
#[test]
fn test_avro_3901_union_schema_round_trip_with_end_null() -> AvroResult<()> {
let schemata: Vec<Schema> =
- Schema::parse_list(&[SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_F_STR]).expect("parsing schemata");
+ Schema::parse_list([SCHEMA_A_STR, SCHEMA_B_STR,
SCHEMA_F_STR]).expect("parsing schemata");
let input = F {
field_union: UnionABNone::A(A { field_a: 23.75 }),
@@ -318,7 +318,7 @@ struct H {
#[test]
fn test_avro_3901_union_schema_as_optional() -> AvroResult<()> {
- let schemata: Vec<Schema> =
Schema::parse_list(&[SCHEMA_H_STR]).expect("parsing schemata");
+ let schemata: Vec<Schema> =
Schema::parse_list([SCHEMA_H_STR]).expect("parsing schemata");
let input = H {
field_union: Some(23),