This is an automated email from the ASF dual-hosted git repository. kriskras99 pushed a commit to branch feat/unvalidated_value in repository https://gitbox.apache.org/repos/asf/avro-rs.git
commit 2bfa677fea1d84d6378b796862e806cddc3ff510 Author: Kriskras99 <[email protected]> AuthorDate: Tue Jan 27 22:34:28 2026 +0100 feat: Add posibility to append values to writer without validating --- avro/src/writer.rs | 109 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 29 deletions(-) diff --git a/avro/src/writer.rs b/avro/src/writer.rs index 1dd3fbf..ae6d5cb 100644 --- a/avro/src/writer.rs +++ b/avro/src/writer.rs @@ -172,8 +172,7 @@ impl<'a, W: Write> Writer<'a, W> { self.schema } - /// Append a compatible value (implementing the `ToAvro` trait) to a `Writer`, also performing - /// schema validation. + /// Append a compatible value to a `Writer`, also performing schema validation. /// /// Returns the number of bytes written (it might be 0, see below). /// @@ -181,10 +180,8 @@ impl<'a, W: Write> Writer<'a, W> { /// internal buffering for performance reasons. If you want to be sure the value has been /// written, then call [`flush`](Writer::flush). pub fn append<T: Into<Value>>(&mut self, value: T) -> AvroResult<usize> { - let n = self.maybe_write_header()?; - let avro = value.into(); - self.append_value_ref(&avro).map(|m| m + n) + self.append_value_ref(&avro) } /// Append a compatible value to a `Writer`, also performing schema validation. @@ -195,9 +192,58 @@ impl<'a, W: Write> Writer<'a, W> { /// internal buffering for performance reasons. If you want to be sure the value has been /// written, then call [`flush`](Writer::flush). pub fn append_value_ref(&mut self, value: &Value) -> AvroResult<usize> { + if let Some(reason) = value.validate_internal( + self.schema, + self.resolved_schema.get_names(), + &self.schema.namespace(), + ) { + return Err(Details::ValidationWithReason { + value: value.clone(), + schema: self.schema.clone(), + reason, + } + .into()); + } + self.unvalidated_append_value_ref(value) + } + + /// Append a compatible value to a `Writer`. + /// + /// This function does **not** validate that the provided value matches the schema. If it does + /// not match, the file will contain corrupt data. Use [`Writer::append_value`] to have the + /// value validated during write or use [`Value::validate`] to validate the value. + /// + /// Returns the number of bytes written (it might be 0, see below). + /// + /// **NOTE**: This function is not guaranteed to perform any actual write, since it relies on + /// internal buffering for performance reasons. If you want to be sure the value has been + /// written, then call [`flush`](Writer::flush). + pub fn unvalidated_append_value<T: Into<Value>>(&mut self, value: T) -> AvroResult<usize> { + let value = value.into(); + self.unvalidated_append_value_ref(&value) + } + + /// Append a compatible value to a `Writer`. + /// + /// This function does **not** validate that the provided value matches the schema. If it does + /// not match, the file will contain corrupt data. Use [`Writer::append_value_ref`] to have the + /// value validated during write or use [`Value::validate`] to validate the value. + /// + /// Returns the number of bytes written (it might be 0, see below). + /// + /// **NOTE**: This function is not guaranteed to perform any actual write, since it relies on + /// internal buffering for performance reasons. If you want to be sure the value has been + /// written, then call [`flush`](Writer::flush). + pub fn unvalidated_append_value_ref(&mut self, value: &Value) -> AvroResult<usize> { let n = self.maybe_write_header()?; + encode_internal( + value, + self.schema, + self.resolved_schema.get_names(), + &self.schema.namespace(), + &mut self.buffer, + )?; - write_value_ref_resolved(self.schema, &self.resolved_schema, value, &mut self.buffer)?; self.num_values += 1; if self.buffer.len() >= self.block_size { @@ -688,29 +734,6 @@ where } } -fn write_value_ref_resolved( - schema: &Schema, - resolved_schema: &ResolvedSchema, - value: &Value, - buffer: &mut Vec<u8>, -) -> AvroResult<usize> { - match value.validate_internal(schema, resolved_schema.get_names(), &schema.namespace()) { - Some(reason) => Err(Details::ValidationWithReason { - value: value.clone(), - schema: schema.clone(), - reason, - } - .into()), - None => encode_internal( - value, - schema, - resolved_schema.get_names(), - &schema.namespace(), - buffer, - ), - } -} - fn write_value_ref_owned_resolved<W: Write>( resolved_schema: &ResolvedOwnedSchema, value: &Value, @@ -1805,4 +1828,32 @@ mod tests { Ok(()) } + + #[test] + fn avro_rs_310_append_unvalidated_value() -> TestResult { + let schema = Schema::String; + let value = Value::Int(1); + + let mut writer = Writer::new(&schema, Vec::new())?; + writer.unvalidated_append_value_ref(&value)?; + writer.unvalidated_append_value(value)?; + let buffer = writer.into_inner()?; + + assert_eq!(&buffer[buffer.len() - 18..buffer.len() - 16], &[2, 2]); + + let mut writer = Writer::new(&schema, Vec::new())?; + let value = Value::Int(1); + let err = writer.append_value_ref(&value).unwrap_err(); + assert_eq!( + err.to_string(), + "Value Int(1) does not match schema String: Reason: Unsupported value-schema combination! Value: Int(1), schema: String" + ); + let err = writer.append(value).unwrap_err(); + assert_eq!( + err.to_string(), + "Value Int(1) does not match schema String: Reason: Unsupported value-schema combination! Value: Int(1), schema: String" + ); + + Ok(()) + } }
