From 0a4f3d5cca897d9faa738cd059bebcbee70b9a8b Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Tue, 21 Nov 2023 10:16:53 +0900 Subject: [PATCH] fix: encode options in unnamed fields properly Special handling for optional values was already done for named fields, but the same behavior was missing from unnamed fields. --- crates/stef-build/src/encode.rs | 13 +- .../compiler__compile@struct_tuple.stef.snap | 16 +- .../compiler__compile@types_generic.stef.snap | 146 ++++++++++++++- .../tests/inputs/types_generic.stef | 8 + .../parser__parse@types_generic.stef.snap | 177 +++++++++++++++++- .../parser__print@types_generic.stef.snap | 4 +- 6 files changed, 356 insertions(+), 8 deletions(-) diff --git a/crates/stef-build/src/encode.rs b/crates/stef-build/src/encode.rs index b42a824..70a29ca 100644 --- a/crates/stef-build/src/encode.rs +++ b/crates/stef-build/src/encode.rs @@ -76,9 +76,18 @@ fn compile_struct_fields(opts: &Opts, fields: &Fields<'_>) -> TokenStream { .map(|(idx, UnnamedField { ty, id, .. })| { let id = proc_macro2::Literal::u32_unsuffixed(id.get()); let idx = proc_macro2::Literal::usize_unsuffixed(idx); - let ty = compile_data_type(opts, ty, quote! { self.#idx }); - quote! { ::stef::buf::encode_field(w, #id, |w| { #ty }); } + if let DataType::Option(ty) = &ty.value { + let ty = compile_data_type(opts, ty, if is_copy(&ty.value) { + quote! { *v } + } else { + quote! { v } + }); + quote! { ::stef::buf::encode_field_option(w, #id, &self.#idx, |w, v| { #ty; }); } + }else{ + let ty = compile_data_type(opts, ty, quote! { self.#idx }); + quote! { ::stef::buf::encode_field(w, #id, |w| { #ty; }); } + } }); quote! { diff --git a/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap index cafc215..59b2879 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap @@ -18,8 +18,20 @@ impl ::stef::Encode for Sample { clippy::too_many_lines, )] fn encode(&self, w: &mut impl ::stef::BufMut) { - ::stef::buf::encode_field(w, 1, |w| { ::stef::buf::encode_u32(w, self.0) }); - ::stef::buf::encode_field(w, 2, |w| { ::stef::buf::encode_bool(w, self.1) }); + ::stef::buf::encode_field( + w, + 1, + |w| { + ::stef::buf::encode_u32(w, self.0); + }, + ); + ::stef::buf::encode_field( + w, + 2, + |w| { + ::stef::buf::encode_bool(w, self.1); + }, + ); ::stef::buf::encode_u32(w, ::stef::buf::END_MARKER); } } diff --git a/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap index 4837487..0db64bd 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap @@ -1,6 +1,6 @@ --- source: crates/stef-build/tests/compiler.rs -description: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}" +description: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}\n\nstruct SampleUnnamed(\n vec @1,\n hash_map @2,\n hash_set @3,\n option @4,\n non_zero @5,\n)" input_file: crates/stef-parser/tests/inputs/types_generic.stef --- #[allow(unused_imports)] @@ -147,4 +147,148 @@ impl ::stef::Decode for Sample { }) } } +#[derive(Clone, Debug, PartialEq)] +#[allow(clippy::module_name_repetitions, clippy::option_option)] +pub struct SampleUnnamed( + pub Vec, + pub ::std::collections::HashMap, + pub ::std::collections::HashSet, + pub Option, + pub ::std::num::NonZeroU32, +); +#[automatically_derived] +impl ::stef::Encode for SampleUnnamed { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn encode(&self, w: &mut impl ::stef::BufMut) { + ::stef::buf::encode_field( + w, + 1, + |w| { + ::stef::buf::encode_vec( + w, + &self.0, + |w, v| { + ::stef::buf::encode_u32(w, *v); + }, + ); + }, + ); + ::stef::buf::encode_field( + w, + 2, + |w| { + ::stef::buf::encode_hash_map( + w, + &self.1, + |w, k| { + ::stef::buf::encode_u32(w, *k); + }, + |w, v| { + ::stef::buf::encode_string(w, &v); + }, + ); + }, + ); + ::stef::buf::encode_field( + w, + 3, + |w| { + ::stef::buf::encode_hash_set( + w, + &self.2, + |w, v| { + ::stef::buf::encode_u32(w, *v); + }, + ); + }, + ); + ::stef::buf::encode_field_option( + w, + 4, + &self.3, + |w, v| { + ::stef::buf::encode_u32(w, *v); + }, + ); + ::stef::buf::encode_field( + w, + 5, + |w| { + ::stef::buf::encode_u32(w, self.4.get()); + }, + ); + ::stef::buf::encode_u32(w, ::stef::buf::END_MARKER); + } +} +#[automatically_derived] +impl ::stef::Decode for SampleUnnamed { + #[allow(clippy::type_complexity, clippy::too_many_lines)] + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + let mut n0: Option> = None; + let mut n1: Option<::std::collections::HashMap> = None; + let mut n2: Option<::std::collections::HashSet> = None; + let mut n3: Option = None; + let mut n4: Option<::std::num::NonZeroU32> = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => { + n0 = Some( + ::stef::buf::decode_vec(r, |r| { ::stef::buf::decode_u32(r) })?, + ); + } + 2 => { + n1 = Some( + ::stef::buf::decode_hash_map( + r, + |r| { ::stef::buf::decode_u32(r) }, + |r| { ::stef::buf::decode_string(r) }, + )?, + ); + } + 3 => { + n2 = Some( + ::stef::buf::decode_hash_set( + r, + |r| { ::stef::buf::decode_u32(r) }, + )?, + ); + } + 4 => n3 = Some(::stef::buf::decode_u32(r)?), + 5 => n4 = Some(::stef::buf::decode_non_zero_u32(r)?), + _ => continue, + } + } + Ok( + Self( + n0 + .ok_or(::stef::buf::Error::MissingField { + id: 1, + name: None, + })?, + n1 + .ok_or(::stef::buf::Error::MissingField { + id: 2, + name: None, + })?, + n2 + .ok_or(::stef::buf::Error::MissingField { + id: 3, + name: None, + })?, + n3, + n4 + .ok_or(::stef::buf::Error::MissingField { + id: 5, + name: None, + })?, + ), + ) + } +} diff --git a/crates/stef-parser/tests/inputs/types_generic.stef b/crates/stef-parser/tests/inputs/types_generic.stef index b1f3484..808eed0 100644 --- a/crates/stef-parser/tests/inputs/types_generic.stef +++ b/crates/stef-parser/tests/inputs/types_generic.stef @@ -5,3 +5,11 @@ struct Sample { f4: option @4, f5: non_zero @5, } + +struct SampleUnnamed( + vec @1, + hash_map @2, + hash_set @3, + option @4, + non_zero @5, +) diff --git a/crates/stef-parser/tests/snapshots/parser__parse@types_generic.stef.snap b/crates/stef-parser/tests/snapshots/parser__parse@types_generic.stef.snap index 99ab514..4d06e6f 100644 --- a/crates/stef-parser/tests/snapshots/parser__parse@types_generic.stef.snap +++ b/crates/stef-parser/tests/snapshots/parser__parse@types_generic.stef.snap @@ -1,13 +1,13 @@ --- source: crates/stef-parser/tests/parser.rs -description: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}" +description: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}\n\nstruct SampleUnnamed(\n vec @1,\n hash_map @2,\n hash_set @3,\n option @4,\n non_zero @5,\n)" input_file: crates/stef-parser/tests/inputs/types_generic.stef --- Schema { path: Some( "types_generic.stef", ), - source: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}\n", + source: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}\n\nstruct SampleUnnamed(\n vec @1,\n hash_map @2,\n hash_set @3,\n option @4,\n non_zero @5,\n)\n", definitions: [ Struct( Struct { @@ -232,5 +232,178 @@ Schema { ), }, ), + Struct( + Struct { + comment: Comment( + [], + ), + attributes: Attributes( + [], + ), + name: Name { + value: "SampleUnnamed", + span: Span { + start: 157, + end: 170, + }, + }, + generics: Generics( + [], + ), + fields: Unnamed( + [ + UnnamedField { + ty: Type { + value: Vec( + Type { + value: U32, + span: Span { + start: 180, + end: 183, + }, + }, + ), + span: Span { + start: 176, + end: 184, + }, + }, + id: Id { + value: 1, + span: Span { + start: 185, + end: 187, + }, + }, + span: Span { + start: 171, + end: 187, + }, + }, + UnnamedField { + ty: Type { + value: HashMap( + ( + Type { + value: U32, + span: Span { + start: 202, + end: 205, + }, + }, + Type { + value: String, + span: Span { + start: 207, + end: 213, + }, + }, + ), + ), + span: Span { + start: 193, + end: 214, + }, + }, + id: Id { + value: 2, + span: Span { + start: 215, + end: 217, + }, + }, + span: Span { + start: 188, + end: 217, + }, + }, + UnnamedField { + ty: Type { + value: HashSet( + Type { + value: U32, + span: Span { + start: 232, + end: 235, + }, + }, + ), + span: Span { + start: 223, + end: 236, + }, + }, + id: Id { + value: 3, + span: Span { + start: 237, + end: 239, + }, + }, + span: Span { + start: 218, + end: 239, + }, + }, + UnnamedField { + ty: Type { + value: Option( + Type { + value: U32, + span: Span { + start: 252, + end: 255, + }, + }, + ), + span: Span { + start: 245, + end: 256, + }, + }, + id: Id { + value: 4, + span: Span { + start: 257, + end: 259, + }, + }, + span: Span { + start: 240, + end: 259, + }, + }, + UnnamedField { + ty: Type { + value: NonZero( + Type { + value: U32, + span: Span { + start: 274, + end: 277, + }, + }, + ), + span: Span { + start: 265, + end: 278, + }, + }, + id: Id { + value: 5, + span: Span { + start: 279, + end: 281, + }, + }, + span: Span { + start: 260, + end: 281, + }, + }, + ], + ), + }, + ), ], } diff --git a/crates/stef-parser/tests/snapshots/parser__print@types_generic.stef.snap b/crates/stef-parser/tests/snapshots/parser__print@types_generic.stef.snap index f9a15d9..62a7b5d 100644 --- a/crates/stef-parser/tests/snapshots/parser__print@types_generic.stef.snap +++ b/crates/stef-parser/tests/snapshots/parser__print@types_generic.stef.snap @@ -1,6 +1,6 @@ --- source: crates/stef-parser/tests/parser.rs -description: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}" +description: "struct Sample {\n f1: vec @1,\n f2: hash_map @2,\n f3: hash_set @3,\n f4: option @4,\n f5: non_zero @5,\n}\n\nstruct SampleUnnamed(\n vec @1,\n hash_map @2,\n hash_set @3,\n option @4,\n non_zero @5,\n)" input_file: crates/stef-parser/tests/inputs/types_generic.stef --- struct Sample { @@ -11,4 +11,6 @@ struct Sample { f5: non_zero @5, } +struct SampleUnnamed(vec @1, hash_map @2, hash_set @3, option @4, non_zero @5) +