From 130a6b543f95ce61a9ee0169aaef4590ed64de5d Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Thu, 28 Dec 2023 10:51:26 +0800 Subject: [PATCH 1/3] feat: more conversion --- .../languages/rust/builder/implementation.rs | 87 +++++++++++++++++++ .../src/generator/languages/rust/generator.rs | 5 ++ 2 files changed, 92 insertions(+) diff --git a/tools/codegen/src/generator/languages/rust/builder/implementation.rs b/tools/codegen/src/generator/languages/rust/builder/implementation.rs index 9995bda..28fab86 100644 --- a/tools/codegen/src/generator/languages/rust/builder/implementation.rs +++ b/tools/codegen/src/generator/languages/rust/builder/implementation.rs @@ -28,6 +28,20 @@ pub(in super::super) trait ImplBuilder: HasName { } } +impl ast::Option_ { + pub(crate) fn gen_from(&self) -> m4::TokenStream { + let entity = entity_name(self.name()); + let item_name = entity_name(self.item().typ().name()); + quote!( + impl From<#item_name> for #entity { + fn from(value: #item_name) -> Self { + Self::new_builder().set(Some(value)).build() + } + } + ) + } +} + impl ImplBuilder for ast::Option_ { fn impl_builder_internal(&self) -> m4::TokenStream { quote!( @@ -47,6 +61,25 @@ impl ImplBuilder for ast::Option_ { } } +impl ast::Union { + pub(crate) fn gen_from(&self) -> m4::TokenStream { + let entity = entity_name(self.name()); + self.items() + .iter() + .map(|item| { + let item_name = entity_name(item.typ().name()); + quote!( + impl From<#item_name> for #entity { + fn from(value: #item_name) -> Self { + Self::new_builder().set(value).build() + } + } + ) + }) + .collect() + } +} + impl ImplBuilder for ast::Union { fn impl_builder_internal(&self) -> m4::TokenStream { quote!( @@ -83,6 +116,36 @@ impl ImplBuilder for ast::Array { } } +impl ast::Array { + pub(crate) fn gen_from(&self) -> m4::TokenStream { + let entity = entity_name(self.name()); + let item_name = entity_name(self.item().typ().name()); + let n = self.item_count(); + let nth = (0..n).map(|i| quote::format_ident!("nth{}", i)); + quote!( + impl From<[#item_name; #n]> for #entity { + fn from(value: [#item_name; #n]) -> Self { + Self::new_builder().set(value).build() + } + } + + impl ::core::convert::TryFrom<&[#item_name]> for #entity { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[#item_name]) -> Result { + // Use TryFrom<&[T]> for &[T; n]. + Ok(Self::new_builder().set(<&[#item_name; #n]>::try_from(value)?.clone()).build()) + } + } + + impl From<#entity> for [#item_name; #n] { + fn from(value: #entity) -> Self { + [#(value.#nth(),)*] + } + } + ) + } +} + impl ImplBuilder for ast::Struct { fn impl_builder_internal(&self) -> m4::TokenStream { let fields = self.fields().iter().map(|f| { @@ -163,6 +226,30 @@ impl ImplBuilder for ast::DynVec { } } +fn gen_from_iter(name: &str, item_name: &str) -> m4::TokenStream { + let entity = entity_name(name); + let item_name = entity_name(item_name); + quote!( + impl ::core::iter::FromIterator<#item_name> for #entity { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } + } + ) +} + +impl ast::FixVec { + pub(crate) fn gen_from_iter(&self) -> m4::TokenStream { + gen_from_iter(self.name(), self.item().typ().name()) + } +} + +impl ast::DynVec { + pub(crate) fn gen_from_iter(&self) -> m4::TokenStream { + gen_from_iter(self.name(), self.item().typ().name()) + } +} + impl ImplBuilder for ast::Table { fn impl_builder_internal(&self) -> m4::TokenStream { if self.fields().is_empty() { diff --git a/tools/codegen/src/generator/languages/rust/generator.rs b/tools/codegen/src/generator/languages/rust/generator.rs index d692973..abf0e96 100644 --- a/tools/codegen/src/generator/languages/rust/generator.rs +++ b/tools/codegen/src/generator/languages/rust/generator.rs @@ -15,6 +15,7 @@ impl Generator for ast::Option_ { writeln!(writer, "{}", self.gen_entity())?; writeln!(writer, "{}", self.gen_reader())?; writeln!(writer, "{}", self.gen_builder())?; + writeln!(writer, "{}", self.gen_from())?; Ok(()) } } @@ -25,6 +26,7 @@ impl Generator for ast::Union { writeln!(writer, "{}", self.gen_reader())?; writeln!(writer, "{}", self.gen_builder())?; writeln!(writer, "{}", self.gen_enumerator())?; + writeln!(writer, "{}", self.gen_from())?; Ok(()) } } @@ -34,6 +36,7 @@ impl Generator for ast::Array { writeln!(writer, "{}", self.gen_entity())?; writeln!(writer, "{}", self.gen_reader())?; writeln!(writer, "{}", self.gen_builder())?; + writeln!(writer, "{}", self.gen_from())?; Ok(()) } } @@ -53,6 +56,7 @@ impl Generator for ast::FixVec { writeln!(writer, "{}", self.gen_reader())?; writeln!(writer, "{}", self.gen_builder())?; writeln!(writer, "{}", self.gen_iterator())?; + writeln!(writer, "{}", self.gen_from_iter())?; Ok(()) } } @@ -63,6 +67,7 @@ impl Generator for ast::DynVec { writeln!(writer, "{}", self.gen_reader())?; writeln!(writer, "{}", self.gen_builder())?; writeln!(writer, "{}", self.gen_iterator())?; + writeln!(writer, "{}", self.gen_from_iter())?; Ok(()) } } From 28798f17f606ba08c2521dc8b953e57035d90d99 Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Thu, 28 Dec 2023 13:37:18 +0800 Subject: [PATCH 2/3] [u8; n] / &[u8] / u8 iterator conversion --- .../languages/rust/builder/implementation.rs | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/tools/codegen/src/generator/languages/rust/builder/implementation.rs b/tools/codegen/src/generator/languages/rust/builder/implementation.rs index 28fab86..e396940 100644 --- a/tools/codegen/src/generator/languages/rust/builder/implementation.rs +++ b/tools/codegen/src/generator/languages/rust/builder/implementation.rs @@ -1,7 +1,7 @@ use proc_macro2 as m4; use quote::quote; -use super::super::utilities::{builder_name, entity_name, field_name, usize_lit}; +use super::super::utilities::{builder_name, entity_name, field_name, reader_name, usize_lit}; use crate::ast::{self as ast, HasName}; pub(in super::super) trait ImplBuilder: HasName { @@ -119,8 +119,48 @@ impl ImplBuilder for ast::Array { impl ast::Array { pub(crate) fn gen_from(&self) -> m4::TokenStream { let entity = entity_name(self.name()); + let reader = reader_name(self.name()); let item_name = entity_name(self.item().typ().name()); let n = self.item_count(); + let maybe_byte_arr = if self.item().typ().name() == "byte" { + quote!( + impl From<[u8; #n]> for #entity { + fn from(value: [u8; #n]) -> Self { + #reader::new_unchecked(&value).to_entity() + } + } + + impl ::core::convert::TryFrom<&[u8]> for #entity { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; #n]>::try_from(value)?.into()) + } + } + + impl From<#entity> for [u8; #n] { + #[track_caller] + fn from(value: #entity) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } + } + + impl<'a> From<#reader<'a>> for &'a [u8; #n] { + #[track_caller] + fn from(value: #reader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } + } + + impl<'a> From<&'a #reader<'a>> for &'a [u8; #n] { + #[track_caller] + fn from(value: &'a #reader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } + } + ) + } else { + quote!() + }; let nth = (0..n).map(|i| quote::format_ident!("nth{}", i)); quote!( impl From<[#item_name; #n]> for #entity { @@ -138,10 +178,13 @@ impl ast::Array { } impl From<#entity> for [#item_name; #n] { + #[track_caller] fn from(value: #entity) -> Self { [#(value.#nth(),)*] } } + + #maybe_byte_arr ) } } @@ -228,6 +271,17 @@ impl ImplBuilder for ast::DynVec { fn gen_from_iter(name: &str, item_name: &str) -> m4::TokenStream { let entity = entity_name(name); + let maybe_byte_vec = if item_name == "byte" { + quote!( + impl ::core::iter::FromIterator for #entity { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter.into_iter().map(Into::into)).build() + } + } + ) + } else { + quote!() + }; let item_name = entity_name(item_name); quote!( impl ::core::iter::FromIterator<#item_name> for #entity { @@ -235,6 +289,8 @@ fn gen_from_iter(name: &str, item_name: &str) -> m4::TokenStream { Self::new_builder().extend(iter).build() } } + + #maybe_byte_vec ) } From 9019c9b4cce5136c29e9470f9be07e1e53fe125a Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Fri, 29 Dec 2023 10:49:08 +0800 Subject: [PATCH 3/3] tests --- examples/ci-tests/tests/build.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/examples/ci-tests/tests/build.rs b/examples/ci-tests/tests/build.rs index d09c1f8..a42d48c 100644 --- a/examples/ci-tests/tests/build.rs +++ b/examples/ci-tests/tests/build.rs @@ -1,5 +1,7 @@ #![allow(clippy::cognitive_complexity)] +use std::{convert::TryFrom, iter::FromIterator}; + use molecule::prelude::*; use molecule_ci_tests::testset; @@ -43,3 +45,19 @@ macro_rules! verify_build_empty { fn build_empty_can_verify() { testset!(all, verify_build_empty); } + +#[test] +fn test_conversion() { + use molecule_ci_tests::types::*; + + assert_eq!( + Byte11::try_from(&[3; 11][..]).unwrap().as_bytes(), + &[3; 11][..], + ); + assert_eq!( + u32::from_le_bytes(Byte4::from(3u32.to_le_bytes()).into()), + 3u32, + ); + let _ = BytesVecOpt::from(BytesVec::from_iter([Bytes::from_iter([3, 4])])); + let _ = UnionA::from(Byte::from(3u8)); +}