@@ -12,6 +12,7 @@ mod assert_zero_copy;
1212mod common;
1313mod schema_read;
1414mod schema_write;
15+ mod uninit_builder;
1516
1617/// Implement `SchemaWrite` for a struct or enum.
1718#[ proc_macro_derive( SchemaWrite , attributes( wincode) ) ]
@@ -32,3 +33,46 @@ pub fn derive_schema_read(input: TokenStream) -> TokenStream {
3233 Err ( e) => e. write_errors ( ) . into ( ) ,
3334 }
3435}
36+
37+ /// Include placement initialization helpers for structs.
38+ ///
39+ /// This generates an `UninitBuilder` for the given struct, providing convenience
40+ /// methods that can avoid a lot of boilerplate when implementing custom
41+ /// `SchemaRead` implementations. In particular, it provides methods that
42+ /// deal with projecting subfields of structs into `MaybeUninit`s. Without this,
43+ /// one would have to write a litany of `&mut *(&raw mut (*dst_ptr).field).cast()` to
44+ /// access MaybeUninit struct fields. It also provides initialization helpers and
45+ /// drop tracking logic.
46+ ///
47+ /// For example:
48+ /// ```ignore
49+ /// #[derive(UninitBuilder)]
50+ /// struct Message {
51+ /// payload: Vec<u8>,
52+ /// bytes: [u8; 32],
53+ /// }
54+ ///
55+ /// unsafe impl<'de, C: Config> SchemaRead<'de, C> for Message {
56+ /// type Dst = Self;
57+ ///
58+ /// fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
59+ /// let msg_builder = MessageUninitBuilder::<C>::from_maybe_uninit_mut(dst);
60+ /// // Deserializes a `Vec<u8>` into the `payload` slot of `Message` and marks the field
61+ /// // as initialized. If the subsequent `read_bytes` call fails, the `payload` field will
62+ /// // be dropped.
63+ /// msg_builder.read_payload(&mut reader)?;
64+ /// msg_builder.read_bytes(reader)?;
65+ /// msg_builder.finish();
66+ /// }
67+ /// }
68+ /// ```
69+ ///
70+ /// We cannot do this for enums, given the lack of facilities for placement initialization.
71+ #[ proc_macro_derive( UninitBuilder , attributes( wincode) ) ]
72+ pub fn derive_uninit_builder ( input : TokenStream ) -> TokenStream {
73+ let input = parse_macro_input ! ( input as DeriveInput ) ;
74+ match uninit_builder:: generate ( input) {
75+ Ok ( tokens) => tokens. into ( ) ,
76+ Err ( e) => e. write_errors ( ) . into ( ) ,
77+ }
78+ }
0 commit comments