diff --git a/digestible/Cargo.toml b/digestible/Cargo.toml index 4b7db9d..6bab75f 100644 --- a/digestible/Cargo.toml +++ b/digestible/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "digestible" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["Wyatt Herkamp "] description = "A more dynamic Hash and Hasher trait for Rust" @@ -16,7 +16,7 @@ rust-version="1.70" [dependencies] digest_0_10 = {package = "digest", version = "0.10", optional = true } byteorder = "1" -digestible-macros= {path="../macros",optional = true, version = "0.2.0" } +digestible-macros= {path="../macros",optional = true, version = "0.2.1" } base64 = { version = "0.21", optional = true } bytes = { version = "1" , optional = true} [dev-dependencies] diff --git a/digestible/src/digester_writer.rs b/digestible/src/digester_writer.rs index a39b5bf..4e2f019 100644 --- a/digestible/src/digester_writer.rs +++ b/digestible/src/digester_writer.rs @@ -161,8 +161,8 @@ impl<'a, T: DigestWriter> DigestWriter for &'a mut T { #[cfg(feature = "alloc")] mod has_alloc { use crate::DigestWriter; - use alloc::vec::Vec; use alloc::boxed::Box; + use alloc::vec::Vec; impl DigestWriter for Vec { fn write(&mut self, data: &[u8]) { @@ -179,4 +179,4 @@ impl DigestWriter for bytes::BytesMut { fn write(&mut self, data: &[u8]) { self.extend_from_slice(data); } -} \ No newline at end of file +} diff --git a/digestible/src/lib.rs b/digestible/src/lib.rs index a8db090..e878a6f 100644 --- a/digestible/src/lib.rs +++ b/digestible/src/lib.rs @@ -135,6 +135,8 @@ pub use digester_writer::DigestWriter; /// ``` /// ### digest_with /// Function provided in the [digest_with](crate::digest_with) module Example: `#[digestible(digest_with = digest_with_hash)]` +/// ### as_ref +/// Will call as_ref on the field before digesting it. Example: `#[digestible(as_ref = TargetType)]` pub use digestible_macros::Digestible; #[cfg(feature = "base64")] #[doc(inline)] diff --git a/digestible/src/to_base64.rs b/digestible/src/to_base64.rs index 973c932..5e00534 100644 --- a/digestible/src/to_base64.rs +++ b/digestible/src/to_base64.rs @@ -71,5 +71,4 @@ where fn digest(self, data: &impl Digestible) -> Self::Target { Self::encode_base64(self.0.digest::(data)) } - } diff --git a/digestible/tests/test.rs b/digestible/tests/test.rs index 4d36cd2..fd4e2f1 100644 --- a/digestible/tests/test.rs +++ b/digestible/tests/test.rs @@ -57,9 +57,11 @@ pub fn test_base64() { pub struct TupleStruct(String); #[derive(Digestible)] #[digestible(hash = LittleEndian, type_header = None)] -pub struct NoHeader{ +pub struct NoHeader { pub name: String, pub id: u32, + #[digestible(as_ref = u32)] + pub as_ref_test: Data, } #[derive(Digestible)] #[digestible(hash = LittleEndian)] @@ -69,6 +71,12 @@ pub enum EnumExample { None, Unit(String), } +pub struct Data(T); +impl AsRef for Data { + fn as_ref(&self) -> &T { + &self.0 + } +} #[test] pub fn hash_test() { let test = EnumExample::One { diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 3b560b7..6a367a1 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "digestible-macros" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["Wyatt Herkamp "] description = "Macros for generating digest implementations" diff --git a/macros/src/fields.rs b/macros/src/fields.rs index 29cbc21..2b41d60 100644 --- a/macros/src/fields.rs +++ b/macros/src/fields.rs @@ -2,22 +2,25 @@ use crate::consts::{digest_with_path, digestible_path}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, ToTokens}; use syn::parse::{Parse, ParseStream}; -use syn::Path; +use syn::{parse_quote, Expr, Path, Type}; mod keywords { use syn::custom_keyword; custom_keyword!(skip); custom_keyword!(with); custom_keyword!(digest_with); + custom_keyword!(as_ref); } #[derive(Debug, Default)] pub struct FieldAttr { pub skip: bool, + pub as_ref: Option, pub digest_with: Option, } impl Parse for FieldAttr { fn parse(input: ParseStream) -> syn::Result { let mut skip = false; + let mut as_ref = None; let mut digest_with: Option = None; while !input.is_empty() { let lookahead = input.lookahead1(); @@ -34,12 +37,20 @@ impl Parse for FieldAttr { let internal_digest_with_path = digest_with_path(input.parse()?); digest_with = Some(internal_digest_with_path); + } else if lookahead.peek(keywords::as_ref) { + let _ = input.parse::()?; + let _: syn::Token![=] = input.parse()?; + as_ref = Some(input.parse()?); } else { return Err(lookahead.error()); } } - let attr = Self { skip, digest_with }; + let attr = Self { + skip, + as_ref, + digest_with, + }; Ok(attr) } } @@ -88,18 +99,26 @@ impl ToTokens for Field<'_> { } let digestible = digestible_path(); let ident = &self.ident; - let ty = &self.ty; + let ty = if let Some(as_ref) = &self.attr.as_ref { + as_ref + } else { + &self.ty + }; let endian = self.endian; let writer = self.writer; + let variable_ref: Expr = if self.attr.as_ref.is_some() { + parse_quote! {#ident.as_ref()} + } else { + parse_quote! {#ident} + }; let result = if let Some(digest_with) = &self.attr.digest_with { quote! { - #digest_with::<#endian,_>(#ident, #writer); + #digest_with::<#endian,_>(#variable_ref, #writer); } } else { - quote! { - <#ty as #digestible>::digest::<#endian, _>(#ident, #writer); - } + quote! {<#ty as #digestible>::digest::<#endian, _>(#variable_ref,#writer);} }; + tokens.extend(result); } }