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

refactor!: borsh_init to borsh(init). #187

Merged
merged 23 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from 10 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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ fn test_simple_struct() {
## Features

Opting out from Serde allows borsh to have some features that currently are not available for serde-compatible serializers.
Currently we support two features: `borsh_init` and `borsh_skip` (the former one not available in Serde).
Currently we support two features: `borsh(init=<your initilization method name>` and `borsh_skip` (the former one not available in Serde).

`borsh_init` allows to automatically run an initialization function right after deserialization. This adds a lot of convenience for objects that are architectured to be used as strictly immutable. Usage example:
`borsh(init=...)` allows to automatically run an initialization function right after deserialization. This adds a lot of convenience for objects that are architectured to be used as strictly immutable. Usage example:

```rust
#[derive(BorshSerialize, BorshDeserialize)]
#[borsh_init(init)]
#[borsh(init=init)]
struct Message {
message: String,
timestamp: u64,
Expand Down
112 changes: 105 additions & 7 deletions borsh-derive/src/internals/attributes/item/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ pub fn check_item_attributes(derive_input: &DeriveInput) -> Result<(), TokenStre
}
if attr.path().is_ident(BORSH.0) {
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
attr.parse_nested_meta(|meta| {
if !meta.path.is_ident(USE_DISCRIMINANT) {
if !meta.path.is_ident(USE_DISCRIMINANT) && !meta.path.is_ident(INIT.0) {
return Err(syn::Error::new(
meta.path.span(),
"`use_discriminant` is the only supported attribute for `borsh`",
"`use_discriminant` or `init` are only supported attributes for `borsh`",
));
}
if meta.path.is_ident(USE_DISCRIMINANT) {
Expand All @@ -29,6 +29,9 @@ pub fn check_item_attributes(derive_input: &DeriveInput) -> Result<(), TokenStre
));
}
}
if meta.path.is_ident(INIT.0) {
let _expr: Expr = meta.value()?.parse()?;
}

Ok(())
})
Expand Down Expand Up @@ -68,6 +71,9 @@ pub fn contains_use_discriminant(input: &ItemEnum) -> Result<bool, syn::Error> {
};
}

if meta.path.is_ident(INIT.0) {
let _value_expr: Expr = meta.value()?.parse()?;
}
Ok(())
})?;
}
Expand All @@ -86,18 +92,22 @@ pub fn contains_use_discriminant(input: &ItemEnum) -> Result<bool, syn::Error> {
}

pub(crate) fn contains_initialize_with(attrs: &[Attribute]) -> Option<Path> {
let mut res = None;
for attr in attrs.iter() {
if attr.path() == INIT {
let mut res = None;
if attr.path() == BORSH {
frol marked this conversation as resolved.
Show resolved Hide resolved
let _ = attr.parse_nested_meta(|meta| {
res = Some(meta.path);
if meta.path.is_ident(INIT.0) {
let value_expr: Path = meta.value()?.parse()?;
res = Some(value_expr);
} else if meta.path.is_ident(USE_DISCRIMINANT) {
let _value_expr: Expr = meta.value()?.parse()?;
};
Ok(())
});
return res;
}
}

None
res
}

#[cfg(test)]
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -199,4 +209,92 @@ mod tests {
let actual = check_item_attributes(&item_enum);
local_insta_assert_snapshot!(actual.unwrap_err().to_token_stream().to_string());
}
#[test]
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
fn test_init_function() {
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
let item_struct = syn::parse2::<DeriveInput>(quote! {
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
#[borsh(init = initializonsdfasfsa)]
frol marked this conversation as resolved.
Show resolved Hide resolved
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
struct A<'a> {
x: u64,
}
})
.unwrap();

let actual = check_item_attributes(&item_struct);
assert!(actual.is_ok());
}

#[test]
fn test_init_function_wrong_format() {
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
let item_struct: DeriveInput = syn::parse2(quote! {
#[derive(BorshDeserialize, Debug)]
#[borsh(init_func = initializonsdfasfsa)]
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
struct A<'a> {
x: u64,
b: B,
y: f32,
z: String,
v: Vec<String>,

}
})
.unwrap();
let actual = check_item_attributes(&item_struct);
local_insta_assert_snapshot!(actual.unwrap_err().to_token_stream().to_string());
}
#[test]
fn test_contains_initialize_with_function() {
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
let item_struct = syn::parse2::<DeriveInput>(quote! {
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
#[borsh(init = initializonsdfasfsa)]
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
struct A<'a> {
x: u64,
}
})
.unwrap();

let actual = contains_initialize_with(&item_struct.attrs);
assert_eq!(
actual.unwrap().to_token_stream().to_string(),
"initializonsdfasfsa"
);
}

#[test]
fn test_contains_initialize_with_function_wrong_format() {
let item_struct: DeriveInput = syn::parse2(quote! {
#[derive(BorshDeserialize, Debug)]
#[borsh(init_func = initializonsdfasfsa)]
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
struct A<'a> {
x: u64,
b: B,
y: f32,
z: String,
v: Vec<String>,

}
})
.unwrap();
let actual = contains_initialize_with(&item_struct.attrs);
assert!(actual.is_none());
}

#[test]
fn test_contains_initialize_with_function_wrong_attr_format() {
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
let item_struct: DeriveInput = syn::parse2(quote! {
#[derive(BorshDeserialize, Debug)]
#[borsh_init(initializonsdfasfsa)]
struct A<'a> {
x: u64,
b: B,
y: f32,
z: String,
v: Vec<String>,

}
})
.unwrap();
let actual = contains_initialize_with(&item_struct.attrs);
assert!(actual.is_none());
}
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
source: borsh-derive/src/internals/attributes/item/mod.rs
expression: actual.unwrap_err().to_token_stream().to_string()
---
:: core :: compile_error ! { "`use_discriminant` is the only supported attribute for `borsh`" }
:: core :: compile_error ! { "`use_discriminant` or `init` are only supported attributes for `borsh`" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: borsh-derive/src/internals/attributes/item/mod.rs
expression: actual.unwrap_err().to_token_stream().to_string()
---
:: core :: compile_error ! { "`use_discriminant` or `init` are only supported attributes for `borsh`" }
2 changes: 1 addition & 1 deletion borsh-derive/src/internals/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub const DESERIALIZE: Symbol = Symbol("deserialize", "deserialize = ...");
/// borsh_skip - field-level only attribute, `BorshSerialize`, `BorshDeserialize`, `BorshSchema` contexts
pub const SKIP: Symbol = Symbol("borsh_skip", "borsh_skip");
/// borsh_init - item-level only attribute `BorshDeserialize` context
pub const INIT: Symbol = Symbol("borsh_init", "borsh_init(...)");
pub const INIT: Symbol = Symbol("init", "init(...)");
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
/// serialize_with - sub-borsh nested meta, field-level only, `BorshSerialize` context
pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with", "serialize_with = ...");
/// deserialize_with - sub-borsh nested meta, field-level only, `BorshDeserialize` context
Expand Down
34 changes: 34 additions & 0 deletions borsh-derive/src/internals/deserialize/enums/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,38 @@ mod tests {

local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap());
}
#[test]
fn borsh_init_func() {
let item_enum: ItemEnum = syn::parse2(quote! {
#[borsh(init = initializon_method, use_discriminant = true)]
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
enum A {
A,
B = 20,
C,
D,
E = 10,
F,
}
})
.unwrap();
let actual = process(&item_enum, Ident::new("borsh", Span::call_site())).unwrap();
local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap());
}
#[test]
fn borsh_init_func_reversed() {
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
let item_enum: ItemEnum = syn::parse2(quote! {
#[borsh(use_discriminant = true, init = initializon_method )]
enum A {
A,
B = 20,
C,
D,
E = 10,
F,
}
})
.unwrap();
let actual = process(&item_enum, Ident::new("borsh", Span::call_site())).unwrap();
local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
source: borsh-derive/src/internals/deserialize/enums/mod.rs
expression: pretty_print_syn_str(&actual).unwrap()
---
impl borsh::de::BorshDeserialize for A {
fn deserialize_reader<R: borsh::__private::maybestd::io::Read>(
reader: &mut R,
) -> ::core::result::Result<Self, borsh::__private::maybestd::io::Error> {
let tag = <u8 as borsh::de::BorshDeserialize>::deserialize_reader(reader)?;
<Self as borsh::de::EnumExt>::deserialize_variant(reader, tag)
}
}
impl borsh::de::EnumExt for A {
fn deserialize_variant<R: borsh::__private::maybestd::io::Read>(
reader: &mut R,
variant_tag: u8,
) -> ::core::result::Result<Self, borsh::__private::maybestd::io::Error> {
let mut return_value = if variant_tag == 0 {
A::A
} else if variant_tag == 20 {
A::B
} else if variant_tag == 20 + 1 {
A::C
} else if variant_tag == 20 + 1 + 1 {
A::D
} else if variant_tag == 10 {
A::E
} else if variant_tag == 10 + 1 {
A::F
} else {
return Err(
borsh::__private::maybestd::io::Error::new(
borsh::__private::maybestd::io::ErrorKind::InvalidData,
borsh::__private::maybestd::format!(
"Unexpected variant tag: {:?}", variant_tag
),
),
)
};
return_value.initializon_method();
Ok(return_value)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
source: borsh-derive/src/internals/deserialize/enums/mod.rs
expression: pretty_print_syn_str(&actual).unwrap()
---
impl borsh::de::BorshDeserialize for A {
fn deserialize_reader<R: borsh::__private::maybestd::io::Read>(
reader: &mut R,
) -> ::core::result::Result<Self, borsh::__private::maybestd::io::Error> {
let tag = <u8 as borsh::de::BorshDeserialize>::deserialize_reader(reader)?;
<Self as borsh::de::EnumExt>::deserialize_variant(reader, tag)
}
}
impl borsh::de::EnumExt for A {
fn deserialize_variant<R: borsh::__private::maybestd::io::Read>(
reader: &mut R,
variant_tag: u8,
) -> ::core::result::Result<Self, borsh::__private::maybestd::io::Error> {
let mut return_value = if variant_tag == 0 {
A::A
} else if variant_tag == 20 {
A::B
} else if variant_tag == 20 + 1 {
A::C
} else if variant_tag == 20 + 1 + 1 {
A::D
} else if variant_tag == 10 {
A::E
} else if variant_tag == 10 + 1 {
A::F
} else {
return Err(
borsh::__private::maybestd::io::Error::new(
borsh::__private::maybestd::io::ErrorKind::InvalidData,
borsh::__private::maybestd::format!(
"Unexpected variant tag: {:?}", variant_tag
),
),
)
};
return_value.initializon_method();
Ok(return_value)
}
}

13 changes: 13 additions & 0 deletions borsh-derive/src/internals/deserialize/structs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,17 @@ mod tests {

local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap());
}
#[test]
fn borsh_init_func() {
let item_enum: ItemStruct = syn::parse2(quote! {
#[borsh(init=initializon_method)]
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
struct A {
x: u64,
y: String,
}
})
.unwrap();
let actual = process(&item_enum, Ident::new("borsh", Span::call_site())).unwrap();
local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
source: borsh-derive/src/internals/deserialize/structs/mod.rs
expression: pretty_print_syn_str(&actual).unwrap()
---
impl borsh::de::BorshDeserialize for A {
fn deserialize_reader<R: borsh::__private::maybestd::io::Read>(
reader: &mut R,
) -> ::core::result::Result<Self, borsh::__private::maybestd::io::Error> {
let mut return_value = Self {
x: borsh::BorshDeserialize::deserialize_reader(reader)?,
y: borsh::BorshDeserialize::deserialize_reader(reader)?,
};
return_value.initializon_method();
Ok(return_value)
}
}

6 changes: 3 additions & 3 deletions borsh-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,12 +303,12 @@ Attribute's value is syn's [Path](syn::Path)-s, enclosed in parentheses.

###### usage

`#[borsh_init(...)]` allows to automatically run an initialization function right after deserialization.
`#[borsh(init=...)]` allows to automatically run an initialization function right after deserialization.
dj8yfo marked this conversation as resolved.
Show resolved Hide resolved
This adds a lot of convenience for objects that are architectured to be used as strictly immutable.

```ignore
#[derive(BorshDeserialize)]
#[borsh_init(init)]
#[borsh(init=init)]
struct Message {
message: String,
timestamp: u64,
Expand Down Expand Up @@ -520,7 +520,7 @@ enum X {
```

*/
#[proc_macro_derive(BorshDeserialize, attributes(borsh_skip, borsh_init, borsh))]
#[proc_macro_derive(BorshDeserialize, attributes(borsh_skip, borsh))]
pub fn borsh_deserialize(input: TokenStream) -> TokenStream {
let name = &crate_name("borsh").unwrap();
let name = match name {
Expand Down
7 changes: 7 additions & 0 deletions borsh/tests/snapshots/test_simple_structs__simple_enum.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
source: borsh/tests/test_simple_structs.rs
expression: encoded_a
---
[
1,
]
Loading
Loading