Skip to content

Commit

Permalink
Merge pull request #80 from blckngm/conversion
Browse files Browse the repository at this point in the history
feat: more conversion
  • Loading branch information
yangby-cryptape authored Jan 4, 2024
2 parents 1b3bfe2 + 9019c9b commit 3b277d8
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 1 deletion.
18 changes: 18 additions & 0 deletions examples/ci-tests/tests/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![allow(clippy::cognitive_complexity)]

use std::{convert::TryFrom, iter::FromIterator};

use molecule::prelude::*;

use molecule_ci_tests::testset;
Expand Down Expand Up @@ -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));
}
145 changes: 144 additions & 1 deletion tools/codegen/src/generator/languages/rust/builder/implementation.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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!(
Expand All @@ -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!(
Expand Down Expand Up @@ -83,6 +116,79 @@ 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<Self, ::core::array::TryFromSliceError> {
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 {
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<Self, ::core::array::TryFromSliceError> {
// 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] {
#[track_caller]
fn from(value: #entity) -> Self {
[#(value.#nth(),)*]
}
}

#maybe_byte_arr
)
}
}

impl ImplBuilder for ast::Struct {
fn impl_builder_internal(&self) -> m4::TokenStream {
let fields = self.fields().iter().map(|f| {
Expand Down Expand Up @@ -163,6 +269,43 @@ 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<u8> for #entity {
fn from_iter<T: IntoIterator<Item = u8>>(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 {
fn from_iter<T: IntoIterator<Item = #item_name>>(iter: T) -> Self {
Self::new_builder().extend(iter).build()
}
}

#maybe_byte_vec
)
}

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() {
Expand Down
5 changes: 5 additions & 0 deletions tools/codegen/src/generator/languages/rust/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}
Expand All @@ -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(())
}
}
Expand All @@ -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(())
}
}
Expand All @@ -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(())
}
}
Expand All @@ -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(())
}
}
Expand Down

0 comments on commit 3b277d8

Please sign in to comment.