diff --git a/Cargo.lock b/Cargo.lock index 88a47f3..d2d26fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,9 +196,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.2" +version = "4.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" +checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" dependencies = [ "clap_builder", "clap_derive", @@ -928,6 +928,7 @@ name = "stef-build" version = "0.1.0" dependencies = [ "indoc", + "insta", "miette", "pretty_assertions", "prettyplease", diff --git a/crates/stef-build/Cargo.toml b/crates/stef-build/Cargo.toml index 0e158ed..0558c27 100644 --- a/crates/stef-build/Cargo.toml +++ b/crates/stef-build/Cargo.toml @@ -18,7 +18,8 @@ thiserror = "1.0.48" [dev-dependencies] indoc = "2.0.3" +insta = { version = "1.31.0", features = ["glob"] } pretty_assertions = "1.4.0" prettyplease = "0.2.15" stef = { path = "../stef" } -syn = "2.0.31" +syn = "2.0.32" diff --git a/crates/stef-build/src/definition.rs b/crates/stef-build/src/definition.rs index b742d1d..39d237f 100644 --- a/crates/stef-build/src/definition.rs +++ b/crates/stef-build/src/definition.rs @@ -7,7 +7,7 @@ use stef_parser::{ use super::{decode, encode}; -pub(crate) fn compile_schema(Schema { definitions }: &Schema<'_>) -> TokenStream { +pub fn compile_schema(Schema { definitions }: &Schema<'_>) -> TokenStream { let definitions = definitions.iter().map(compile_definition); quote! { #(#definitions)* } diff --git a/crates/stef-build/src/lib.rs b/crates/stef-build/src/lib.rs index 7e9a34f..1935a1a 100644 --- a/crates/stef-build/src/lib.rs +++ b/crates/stef-build/src/lib.rs @@ -6,6 +6,8 @@ use std::path::{Path, PathBuf}; use stef_parser::Schema; use thiserror::Error; +pub use self::definition::compile_schema; + mod decode; mod definition; mod encode; diff --git a/crates/stef-build/tests/inputs b/crates/stef-build/tests/inputs new file mode 120000 index 0000000..7089636 --- /dev/null +++ b/crates/stef-build/tests/inputs @@ -0,0 +1 @@ +../../stef-parser/tests/inputs \ No newline at end of file diff --git a/crates/stef-build/tests/parser.rs b/crates/stef-build/tests/parser.rs new file mode 100644 index 0000000..fc9afe0 --- /dev/null +++ b/crates/stef-build/tests/parser.rs @@ -0,0 +1,16 @@ +use std::fs; + +use insta::{assert_snapshot, glob}; +use stef_parser::Schema; + +#[test] +fn compile_schema() { + glob!("inputs/types-*.stef", |path| { + let input = fs::read_to_string(path).unwrap(); + let value = Schema::parse(input.as_str()).unwrap(); + let value = stef_build::compile_schema(&value); + let value = prettyplease::unparse(&syn::parse2(value).unwrap()); + + assert_snapshot!("compile", format!("{value}"), input.trim()); + }); +} diff --git a/crates/stef-build/tests/snapshots/parser__compile@types-basic.stef.snap b/crates/stef-build/tests/snapshots/parser__compile@types-basic.stef.snap new file mode 100644 index 0000000..f855d4f --- /dev/null +++ b/crates/stef-build/tests/snapshots/parser__compile@types-basic.stef.snap @@ -0,0 +1,245 @@ +--- +source: crates/stef-build/tests/parser.rs +expression: "struct Sample {\n f01: bool @1,\n f02: u8 @2,\n f03: u16 @3,\n f04: u32 @4,\n f05: u64 @5,\n f06: u128 @6,\n f07: i8 @7,\n f08: i16 @8,\n f09: i32 @9,\n f10: i64 @10,\n f11: i128 @11,\n f12: f32 @12,\n f13: f64 @13,\n f14: string @14,\n f15: &string @15,\n f16: bytes @16,\n f17: &bytes @17,\n f18: box @18,\n f19: box @19,\n f20: (u32, u32, u32) @20,\n f21: [u32; 12] @21,\n}" +input_file: crates/stef-parser/tests/inputs/types-basic.stef +--- +pub struct Sample { + pub f01: bool, + pub f02: u8, + pub f03: u16, + pub f04: u32, + pub f05: u64, + pub f06: u128, + pub f07: i8, + pub f08: i16, + pub f09: i32, + pub f10: i64, + pub f11: i128, + pub f12: f32, + pub f13: f64, + pub f14: String, + pub f15: String, + pub f16: Vec, + pub f17: Vec, + pub f18: Box, + pub f19: Box<[u8]>, + pub f20: (u32, u32, u32), + pub f21: [u32; 12], +} +impl ::stef::Encode for Sample { + fn encode(&self, w: &mut impl ::stef::BufMut) { + ::stef::buf::encode_field(w, 1, |w| { ::stef::buf::encode_bool(w, self.f01) }); + ::stef::buf::encode_field(w, 2, |w| { ::stef::buf::encode_u8(w, self.f02) }); + ::stef::buf::encode_field(w, 3, |w| { ::stef::buf::encode_u16(w, self.f03) }); + ::stef::buf::encode_field(w, 4, |w| { ::stef::buf::encode_u32(w, self.f04) }); + ::stef::buf::encode_field(w, 5, |w| { ::stef::buf::encode_u64(w, self.f05) }); + ::stef::buf::encode_field(w, 6, |w| { ::stef::buf::encode_u128(w, self.f06) }); + ::stef::buf::encode_field(w, 7, |w| { ::stef::buf::encode_i8(w, self.f07) }); + ::stef::buf::encode_field(w, 8, |w| { ::stef::buf::encode_i16(w, self.f08) }); + ::stef::buf::encode_field(w, 9, |w| { ::stef::buf::encode_i32(w, self.f09) }); + ::stef::buf::encode_field(w, 10, |w| { ::stef::buf::encode_i64(w, self.f10) }); + ::stef::buf::encode_field(w, 11, |w| { ::stef::buf::encode_i128(w, self.f11) }); + ::stef::buf::encode_field(w, 12, |w| { ::stef::buf::encode_f32(w, self.f12) }); + ::stef::buf::encode_field(w, 13, |w| { ::stef::buf::encode_f64(w, self.f13) }); + ::stef::buf::encode_field( + w, + 14, + |w| { ::stef::buf::encode_string(w, &self.f14) }, + ); + ::stef::buf::encode_field( + w, + 15, + |w| { ::stef::buf::encode_string(w, &self.f15) }, + ); + ::stef::buf::encode_field( + w, + 16, + |w| { ::stef::buf::encode_bytes(w, &self.f16) }, + ); + ::stef::buf::encode_field( + w, + 17, + |w| { ::stef::buf::encode_bytes(w, &self.f17) }, + ); + ::stef::buf::encode_field( + w, + 18, + |w| { ::stef::buf::encode_string(w, &*self.f18) }, + ); + ::stef::buf::encode_field( + w, + 19, + |w| { ::stef::buf::encode_bytes(w, &*self.f19) }, + ); + ::stef::buf::encode_field( + w, + 20, + |w| { ::stef::buf::encode_tuple3(w, &self.f20) }, + ); + ::stef::buf::encode_field( + w, + 21, + |w| { ::stef::buf::encode_array(w, &self.f21) }, + ); + } +} +impl ::stef::Decode for Sample { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + let mut f01: Option = None; + let mut f02: Option = None; + let mut f03: Option = None; + let mut f04: Option = None; + let mut f05: Option = None; + let mut f06: Option = None; + let mut f07: Option = None; + let mut f08: Option = None; + let mut f09: Option = None; + let mut f10: Option = None; + let mut f11: Option = None; + let mut f12: Option = None; + let mut f13: Option = None; + let mut f14: Option = None; + let mut f15: Option = None; + let mut f16: Option> = None; + let mut f17: Option> = None; + let mut f18: Option> = None; + let mut f19: Option> = None; + let mut f20: Option<(u32, u32, u32)> = None; + let mut f21: Option<[u32; 12]> = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => f01 = Some(::stef::buf::decode_bool(r)?), + 2 => f02 = Some(::stef::buf::decode_u8(r)?), + 3 => f03 = Some(::stef::buf::decode_u16(r)?), + 4 => f04 = Some(::stef::buf::decode_u32(r)?), + 5 => f05 = Some(::stef::buf::decode_u64(r)?), + 6 => f06 = Some(::stef::buf::decode_u128(r)?), + 7 => f07 = Some(::stef::buf::decode_i8(r)?), + 8 => f08 = Some(::stef::buf::decode_i16(r)?), + 9 => f09 = Some(::stef::buf::decode_i32(r)?), + 10 => f10 = Some(::stef::buf::decode_i64(r)?), + 11 => f11 = Some(::stef::buf::decode_i128(r)?), + 12 => f12 = Some(::stef::buf::decode_f32(r)?), + 13 => f13 = Some(::stef::buf::decode_f64(r)?), + 14 => f14 = Some(::stef::buf::decode_string(r)?), + 15 => f15 = Some(::stef::buf::decode_string(r)?), + 16 => f16 = Some(::stef::buf::decode_bytes(r)?), + 17 => f17 = Some(::stef::buf::decode_bytes(r)?), + 18 => f18 = Some(Box < str > ::decode(r)?), + 19 => f19 = Some(Box < [u8] > ::decode(r)?), + 20 => f20 = Some(::stef::buf::decode_tuple3(r)?), + 21 => f21 = Some(::stef::buf::decode_array(r)?), + _ => continue, + } + } + Ok(Self { + f01: f01 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 1, + name: Some("f01"), + }), + f02: f02 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 2, + name: Some("f02"), + }), + f03: f03 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 3, + name: Some("f03"), + }), + f04: f04 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 4, + name: Some("f04"), + }), + f05: f05 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 5, + name: Some("f05"), + }), + f06: f06 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 6, + name: Some("f06"), + }), + f07: f07 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 7, + name: Some("f07"), + }), + f08: f08 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 8, + name: Some("f08"), + }), + f09: f09 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 9, + name: Some("f09"), + }), + f10: f10 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 10, + name: Some("f10"), + }), + f11: f11 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 11, + name: Some("f11"), + }), + f12: f12 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 12, + name: Some("f12"), + }), + f13: f13 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 13, + name: Some("f13"), + }), + f14: f14 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 14, + name: Some("f14"), + }), + f15: f15 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 15, + name: Some("f15"), + }), + f16: f16 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 16, + name: Some("f16"), + }), + f17: f17 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 17, + name: Some("f17"), + }), + f18: f18 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 18, + name: Some("f18"), + }), + f19: f19 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 19, + name: Some("f19"), + }), + f20: f20 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 20, + name: Some("f20"), + }), + f21: f21 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 21, + name: Some("f21"), + }), + }) + } +} + diff --git a/crates/stef-build/tests/snapshots/parser__compile@types-generic.stef.snap b/crates/stef-build/tests/snapshots/parser__compile@types-generic.stef.snap new file mode 100644 index 0000000..f695d5d --- /dev/null +++ b/crates/stef-build/tests/snapshots/parser__compile@types-generic.stef.snap @@ -0,0 +1,73 @@ +--- +source: crates/stef-build/tests/parser.rs +expression: "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}" +input_file: crates/stef-parser/tests/inputs/types-generic.stef +--- +pub struct Sample { + pub f1: Vec, + pub f2: HashMap, + pub f3: HashSet, + pub f4: Option, + pub f5: NonZeroU32, +} +impl ::stef::Encode for Sample { + fn encode(&self, w: &mut impl ::stef::BufMut) { + ::stef::buf::encode_field(w, 1, |w| { ::stef::buf::encode_vec(w, &self.f1) }); + ::stef::buf::encode_field( + w, + 2, + |w| { ::stef::buf::encode_hash_map(w, self.f2) }, + ); + ::stef::buf::encode_field( + w, + 3, + |w| { ::stef::buf::encode_hash_set(w, self.f3) }, + ); + ::stef::buf::encode_field(w, 4, |w| { ::stef::buf::encode_option(w, self.f4) }); + ::stef::buf::encode_field(w, 5, |w| { self.f5.encode(w) }); + } +} +impl ::stef::Decode for Sample { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + let mut f1: Option> = None; + let mut f2: Option> = None; + let mut f3: Option> = None; + let mut f4: Option> = None; + let mut f5: Option = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => f1 = Some(::stef::buf::decode_vec(r)?), + 2 => f2 = Some(::stef::buf::decode_hash_map(r)?), + 3 => f3 = Some(::stef::buf::decode_hash_set(r)?), + 4 => f4 = Some(::stef::buf::decode_u32(r)?), + 5 => f5 = Some(NonZeroU32::decode(r)?), + _ => continue, + } + } + Ok(Self { + f1: f1 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 1, + name: Some("f1"), + }), + f2: f2 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 2, + name: Some("f2"), + }), + f3: f3 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 3, + name: Some("f3"), + }), + f4, + f5: f5 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 5, + name: Some("f5"), + }), + }) + } +} + diff --git a/crates/stef-build/tests/snapshots/parser__compile@types-nested.stef.snap b/crates/stef-build/tests/snapshots/parser__compile@types-nested.stef.snap new file mode 100644 index 0000000..8abef5e --- /dev/null +++ b/crates/stef-build/tests/snapshots/parser__compile@types-nested.stef.snap @@ -0,0 +1,33 @@ +--- +source: crates/stef-build/tests/parser.rs +expression: "struct Sample {\n value: vec>>>> @1,\n}" +input_file: crates/stef-parser/tests/inputs/types-nested.stef +--- +pub struct Sample { + pub value: Vec>>>, +} +impl ::stef::Encode for Sample { + fn encode(&self, w: &mut impl ::stef::BufMut) { + ::stef::buf::encode_field(w, 1, |w| { ::stef::buf::encode_vec(w, &self.value) }); + } +} +impl ::stef::Decode for Sample { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + let mut value: Option>>>> = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => value = Some(::stef::buf::decode_vec(r)?), + _ => continue, + } + } + Ok(Self { + value: value + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 1, + name: Some("value"), + }), + }) + } +} + diff --git a/crates/stef-build/tests/snapshots/parser__compile@types-ref.stef.snap b/crates/stef-build/tests/snapshots/parser__compile@types-ref.stef.snap new file mode 100644 index 0000000..feac692 --- /dev/null +++ b/crates/stef-build/tests/snapshots/parser__compile@types-ref.stef.snap @@ -0,0 +1,42 @@ +--- +source: crates/stef-build/tests/parser.rs +expression: "struct Sample {\n basic: Test123 @1,\n with_generics: KeyValue @2,\n}" +input_file: crates/stef-parser/tests/inputs/types-ref.stef +--- +pub struct Sample { + pub basic: Test123, + pub with_generics: KeyValue, +} +impl ::stef::Encode for Sample { + fn encode(&self, w: &mut impl ::stef::BufMut) { + ::stef::buf::encode_field(w, 1, |w| { self.basic.encode(w) }); + ::stef::buf::encode_field(w, 2, |w| { self.with_generics.encode(w) }); + } +} +impl ::stef::Decode for Sample { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + let mut basic: Option = None; + let mut with_generics: Option> = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => basic = Some(Test123::decode(r)?), + 2 => with_generics = Some(KeyValue::decode(r)?), + _ => continue, + } + } + Ok(Self { + basic: basic + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 1, + name: Some("basic"), + }), + with_generics: with_generics + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 2, + name: Some("with_generics"), + }), + }) + } +} + diff --git a/crates/stef-cli/Cargo.toml b/crates/stef-cli/Cargo.toml index 1c7c266..1c59460 100644 --- a/crates/stef-cli/Cargo.toml +++ b/crates/stef-cli/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true include = ["src/**/*"] [dependencies] -clap = { version = "4.4.2", features = ["derive", "wrap_help"] } +clap = { version = "4.4.3", features = ["derive", "wrap_help"] } color-eyre.workspace = true miette = { workspace = true, features = ["fancy-no-backtrace"] } mimalloc = "0.1.38" diff --git a/crates/stef-derive/Cargo.toml b/crates/stef-derive/Cargo.toml index 2dac851..0ae2188 100644 --- a/crates/stef-derive/Cargo.toml +++ b/crates/stef-derive/Cargo.toml @@ -15,4 +15,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.66" quote = "1.0.33" -syn = "2.0.31" +syn = "2.0.32"