Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: more conversion #80

Merged
merged 3 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading