diff --git a/src/de/mod.rs b/src/de/mod.rs index 59bdee6..34c6acf 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -91,7 +91,7 @@ pub struct DeserializerState<'s, R> { /// Schema + other configs for deserialization #[derive(Clone)] pub struct DeserializerConfig<'s> { - schema_root: &'s SchemaNode<'s>, + schema_root: NodeRef<'s>, /// If a sequence turns out to be longer than this during deserialization, /// we will throw an error instead. /// @@ -115,7 +115,7 @@ impl<'s> DeserializerConfig<'s> { pub fn new(schema: &'s Schema) -> Self { Self::from_schema_node(schema.root()) } - pub(crate) fn from_schema_node(schema_root: &'s SchemaNode<'s>) -> Self { + pub(crate) fn from_schema_node(schema_root: NodeRef<'s>) -> Self { Self { schema_root, max_seq_size: 1_000_000_000, @@ -129,7 +129,7 @@ impl<'s, 'de, R: ReadSlice<'de>> DeserializerState<'s, R> { Self::from_schema_node(r, schema.root()) } - pub(crate) fn from_schema_node(r: R, schema_root: &'s SchemaNode<'s>) -> Self { + pub(crate) fn from_schema_node(r: R, schema_root: NodeRef<'s>) -> Self { Self::with_config(r, DeserializerConfig::from_schema_node(schema_root)) } @@ -139,7 +139,7 @@ impl<'s, 'de, R: ReadSlice<'de>> DeserializerState<'s, R> { pub fn deserializer<'r>(&'r mut self) -> DatumDeserializer<'r, 's, R> { DatumDeserializer { - schema_node: self.config.schema_root, + schema_node: self.config.schema_root.as_ref(), allowed_depth: AllowedDepth::new(self.config.allowed_depth), state: self, } diff --git a/src/object_container_file_encoding/mod.rs b/src/object_container_file_encoding/mod.rs index 355b0b2..05fc696 100644 --- a/src/object_container_file_encoding/mod.rs +++ b/src/object_container_file_encoding/mod.rs @@ -173,10 +173,12 @@ struct Metadata { #[serde(flatten)] user_metadata: M, } -const METADATA_SCHEMA: &crate::schema::self_referential::SchemaNode = - &crate::schema::self_referential::SchemaNode::Map( - crate::schema::self_referential::NodeRef::from_static( - &crate::schema::self_referential::SchemaNode::Bytes, +const METADATA_SCHEMA: crate::schema::self_referential::NodeRef<'static> = + crate::schema::self_referential::NodeRef::from_static( + &crate::schema::self_referential::SchemaNode::Map( + crate::schema::self_referential::NodeRef::from_static( + &crate::schema::self_referential::SchemaNode::Bytes, + ), ), ); diff --git a/src/object_container_file_encoding/reader/mod.rs b/src/object_container_file_encoding/reader/mod.rs index 624ce6e..6ad1743 100644 --- a/src/object_container_file_encoding/reader/mod.rs +++ b/src/object_container_file_encoding/reader/mod.rs @@ -173,18 +173,11 @@ where .read_const_size_buf::<16>() .map_err(FailedToInitializeReader::FailedToDeserializeHeader)?; - // Build a `&'static SchemaNode` from the `Arc` (`'static` is fake) // Safety: we don't drop the schema until this is dropped // This is useful to be able to store a DeserializerState directly in here, // which will avoid additional &mut levels, allowing for highest performance and // ergonomics - let schema_root: &'static schema::self_referential::SchemaNode<'static> = unsafe { - let schema = &*(&*schema as *const Schema); - let a: *const schema::self_referential::SchemaNode<'_> = - schema.root() as *const schema::self_referential::SchemaNode<'_>; - let b: *const schema::self_referential::SchemaNode<'static> = a as *const _; - &*b - }; + let schema_root = unsafe { schema.root_with_fake_static_lifetime() }; Ok(( Self { diff --git a/src/object_container_file_encoding/writer/mod.rs b/src/object_container_file_encoding/writer/mod.rs index a6e1b9f..6d3e930 100644 --- a/src/object_container_file_encoding/writer/mod.rs +++ b/src/object_container_file_encoding/writer/mod.rs @@ -159,7 +159,9 @@ impl<'c, 's> WriterBuilder<'c, 's> { codec: self.compression.codec(), user_metadata: metadata, }) - .serialize(header_serializer_state.serializer_overriding_schema_root(METADATA_SCHEMA)) + .serialize( + header_serializer_state.serializer_overriding_schema_root(METADATA_SCHEMA.as_ref()), + ) .map_err(|ser_error| { ::custom(format_args!( "Failed to serialize object container file header metadata: {ser_error}" diff --git a/src/schema/self_referential.rs b/src/schema/self_referential.rs index 6597c3d..b1e8e34 100644 --- a/src/schema/self_referential.rs +++ b/src/schema/self_referential.rs @@ -43,12 +43,26 @@ impl Schema { /// [`Schema`]. /// /// The root node represents the whole schema. - pub(crate) fn root<'a>(&'a self) -> &'a SchemaNode<'a> { + pub(crate) fn root<'a>(&'a self) -> NodeRef<'a> { // the signature of this function downgrades the fake 'static lifetime in a way // that makes it correct - self.nodes - .first() - .expect("Schema must have at least one node (the root)") + assert!( + !self.nodes.is_empty(), + "Schema must have at least one node (the root)" + ); + // SAFETY: bounds checked + unsafe { NodeRef::new(self.nodes.as_ptr() as *mut _) } + } + + /// SAFETY: this `NodeRef` must never be dereferenced after the + /// corresponding schema was dropped. + pub(crate) unsafe fn root_with_fake_static_lifetime(&self) -> NodeRef<'static> { + assert!( + !self.nodes.is_empty(), + "Schema must have at least one node (the root)" + ); + // SAFETY: bounds checked + unsafe { NodeRef::new(self.nodes.as_ptr() as *mut _) } } /// Obtain the JSON for this schema @@ -492,7 +506,7 @@ impl TryFrom for Schema { impl std::fmt::Debug for Schema { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - as std::fmt::Debug>::fmt(self.root(), f) + as std::fmt::Debug>::fmt(self.root().as_ref(), f) } } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index acf92d0..c01c832 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -160,7 +160,7 @@ impl<'c, 's, W: std::io::Write> SerializerState<'c, 's, W> { pub fn serializer<'r>(&'r mut self) -> DatumSerializer<'r, 'c, 's, W> { DatumSerializer { - schema_node: self.config.schema().root(), + schema_node: self.config.schema().root().as_ref(), state: self, } }