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

Decode context #710

Open
wants to merge 3 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Expand Up @@ -37,6 +37,7 @@ unty = "0.0.3"

# Used for tests
[dev-dependencies]
ouroboros = "0.18.3"
serde_derive = "1.0"
serde_json = { version = "1.0", default-features = false }
tempfile = "3.2"
Expand All @@ -47,6 +48,7 @@ chrono = { version = "0.4", features = ["serde"] }
glam = { version = "0.25", features = ["serde"] }
bincode_1 = { version = "1.3", package = "bincode" }
serde = { version = "1.0", features = ["derive"] }
bumpalo = { version = "3.16.0", features = ["collections"] }

[[bench]]
name = "varint"
Expand Down
4 changes: 2 additions & 2 deletions compatibility/src/lib.rs
Expand Up @@ -11,7 +11,7 @@ mod sway;
pub fn test_same_with_config<T, C, O>(t: &T, bincode_1_options: O, bincode_2_config: C)
where
T: bincode_2::Encode
+ bincode_2::Decode
+ bincode_2::Decode<()>
+ serde::Serialize
+ serde::de::DeserializeOwned
+ core::fmt::Debug
Expand Down Expand Up @@ -60,7 +60,7 @@ where
pub fn test_same<T>(t: T)
where
T: bincode_2::Encode
+ bincode_2::Decode
+ bincode_2::Decode<()>
+ serde::Serialize
+ serde::de::DeserializeOwned
+ core::fmt::Debug
Expand Down
1 change: 1 addition & 0 deletions compatibility/src/sway.rs
Expand Up @@ -32,6 +32,7 @@ pub enum FTXresponse<T> {
Error(FTXresponseFailure),
}


#[derive(
bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq,
)]
Expand Down
2 changes: 1 addition & 1 deletion derive/Cargo.toml
Expand Up @@ -19,4 +19,4 @@ description = "Implementation of #[derive(Encode, Decode)] for bincode"
proc-macro = true

[dependencies]
virtue = "0.0.16"
virtue = { git = "https://github.com/branchseer/virtue", branch = "with_impl_generics" }
12 changes: 12 additions & 0 deletions derive/src/attribute.rs
@@ -1,10 +1,12 @@
use proc_macro::Literal;

Check warning on line 1 in derive/src/attribute.rs

View workflow job for this annotation

GitHub Actions / Check (beta)

the item `Literal` is imported redundantly

Check warning on line 1 in derive/src/attribute.rs

View workflow job for this annotation

GitHub Actions / Check (beta)

the item `Literal` is imported redundantly
use virtue::prelude::*;
use virtue::utils::{parse_tagged_attribute, ParsedAttribute};

pub struct ContainerAttributes {
pub crate_name: String,
pub bounds: Option<(String, Literal)>,
pub decode_bounds: Option<(String, Literal)>,
pub decode_context: Option<(String, Literal)>,
pub borrow_decode_bounds: Option<(String, Literal)>,
pub encode_bounds: Option<(String, Literal)>,
}
Expand All @@ -15,6 +17,7 @@
crate_name: "::bincode".to_string(),
bounds: None,
decode_bounds: None,
decode_context: None,
encode_bounds: None,
borrow_decode_bounds: None,
}
Expand Down Expand Up @@ -56,6 +59,15 @@
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Property(key, val) if key.to_string() == "decode_context" => {
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
result.decode_context =
Some((val_string[1..val_string.len() - 1].to_string(), val));
} else {
return Err(Error::custom_at("Should be a literal str", val.span()));
}
}
ParsedAttribute::Property(key, val) if key.to_string() == "encode_bounds" => {
let val_string = val.to_string();
if val_string.starts_with('"') && val_string.ends_with('"') {
Expand Down
51 changes: 38 additions & 13 deletions derive/src/derive_enum.rs
Expand Up @@ -219,25 +219,37 @@ impl DeriveEnum {
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
let crate_name = self.attributes.crate_name.as_str();

let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Ctx"
};
// Remember to keep this mostly in sync with generate_borrow_decode

let enum_name = generator.target_name().to_string();

generator
.impl_for(format!("{}::Decode", crate_name))
let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name));


if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Ctx"]);
}

impl_for
.with_trait_generics([decode_context])
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::Decode", crate_name))?;
where_constraints.push_constraint(g, format!("{}::Decode<__Ctx>", crate_name))?;
}
}
Ok(())
})?
.generate_fn("decode")
.with_generic_deps("__D", [format!("{}::de::Decoder", crate_name)])
.with_generic_deps("__D", [format!("{}::de::Decoder<Ctx = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_builder| {
Expand All @@ -249,7 +261,7 @@ impl DeriveEnum {
} else {
fn_builder
.push_parsed(format!(
"let variant_index = <u32 as {}::Decode>::decode(decoder)?;",
"let variant_index = <u32 as {}::Decode::<__D::Ctx>>::decode(decoder)?;",
crate_name
))?;
fn_builder.push_parsed("match variant_index")?;
Expand Down Expand Up @@ -286,13 +298,13 @@ impl DeriveEnum {
if attributes.with_serde {
variant_body
.push_parsed(format!(
"<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?.0,",
"<{0}::serde::Compat<_> as {0}::Decode::<__D::Ctx>>::decode(decoder)?.0,",
crate_name
))?;
} else {
variant_body
.push_parsed(format!(
"{}::Decode::decode(decoder)?,",
"{}::Decode::<__D::Ctx>::decode(decoder)?,",
crate_name
))?;
}
Expand All @@ -318,17 +330,30 @@ impl DeriveEnum {
pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
let crate_name = &self.attributes.crate_name;

let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Ctx"
};

// Remember to keep this mostly in sync with generate_decode
let enum_name = generator.target_name().to_string();

generator.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
let mut impl_for = generator
.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
.with_trait_generics([decode_context]);
if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Ctx"]);
}

impl_for
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap();
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap();
}
for lt in generics.iter_lifetimes() {
where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?;
Expand All @@ -337,7 +362,7 @@ impl DeriveEnum {
Ok(())
})?
.generate_fn("borrow_decode")
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)])
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Ctx = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_builder| {
Expand All @@ -348,7 +373,7 @@ impl DeriveEnum {
))?;
} else {
fn_builder
.push_parsed(format!("let variant_index = <u32 as {}::Decode>::decode(decoder)?;", crate_name))?;
.push_parsed(format!("let variant_index = <u32 as {}::Decode::<__D::Ctx>>::decode(decoder)?;", crate_name))?;
fn_builder.push_parsed("match variant_index")?;
fn_builder.group(Delimiter::Brace, |variant_case| {
for (mut variant_index, variant) in self.iter_fields() {
Expand Down Expand Up @@ -382,9 +407,9 @@ impl DeriveEnum {
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
if attributes.with_serde {
variant_body
.push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?.0,", crate_name))?;
.push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<__D::Ctx>>::borrow_decode(decoder)?.0,", crate_name))?;
} else {
variant_body.push_parsed(format!("{}::BorrowDecode::borrow_decode(decoder)?,", crate_name))?;
variant_body.push_parsed(format!("{}::BorrowDecode::<__D::Ctx>::borrow_decode(decoder)?,", crate_name))?;
}
}
}
Expand Down
53 changes: 39 additions & 14 deletions derive/src/derive_struct.rs
@@ -1,6 +1,6 @@
use crate::attribute::{ContainerAttributes, FieldAttributes};
use virtue::generate::Generator;

Check warning on line 2 in derive/src/derive_struct.rs

View workflow job for this annotation

GitHub Actions / Check (beta)

the item `Generator` is imported redundantly

Check warning on line 2 in derive/src/derive_struct.rs

View workflow job for this annotation

GitHub Actions / Check (beta)

the item `Generator` is imported redundantly
use virtue::parse::Fields;

Check warning on line 3 in derive/src/derive_struct.rs

View workflow job for this annotation

GitHub Actions / Check (beta)

the item `Fields` is imported redundantly

Check warning on line 3 in derive/src/derive_struct.rs

View workflow job for this annotation

GitHub Actions / Check (beta)

the item `Fields` is imported redundantly
use virtue::prelude::*;

pub(crate) struct DeriveStruct {
Expand Down Expand Up @@ -67,22 +67,32 @@
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
// Remember to keep this mostly in sync with generate_borrow_decode
let crate_name = &self.attributes.crate_name;
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Ctx"
};

generator
.impl_for(format!("{}::Decode", crate_name))
let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name));
if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Ctx"]);
}

impl_for
.with_trait_generics([decode_context])
.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap();
where_constraints.push_constraint(g, format!("{}::Decode<{}>", crate_name, decode_context)).unwrap();
}
}
Ok(())
})?
.generate_fn("decode")
.with_generic_deps("__D", [format!("{}::de::Decoder", crate_name)])
.with_generic_deps("__D", [format!("{}::de::Decoder<Ctx = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_body| {
Expand All @@ -103,9 +113,10 @@
if attributes.with_serde {
struct_body
.push_parsed(format!(
"{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,",
"{1}: (<{0}::serde::Compat<_> as {0}::Decode::<{2}>>::decode(decoder)?).0,",
crate_name,
field
field,
decode_context,
))?;
} else {
struct_body
Expand All @@ -131,15 +142,27 @@
// Remember to keep this mostly in sync with generate_decode
let crate_name = self.attributes.crate_name;

generator
.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
decode_context.as_str()
} else {
"__Ctx"
};

let mut impl_for =
generator.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"]).with_trait_generics([decode_context]);
if self.attributes.decode_context.is_none() {
impl_for = impl_for.with_impl_generics(["__Ctx"]);
}

impl_for

.modify_generic_constraints(|generics, where_constraints| {
if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
where_constraints.clear();
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
} else {
for g in generics.iter_generics() {
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap();
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap();
}
for lt in generics.iter_lifetimes() {
where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?;
Expand All @@ -148,7 +171,7 @@
Ok(())
})?
.generate_fn("borrow_decode")
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)])
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Ctx = {}>", crate_name, decode_context)])
.with_arg("decoder", "&mut __D")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
.body(|fn_body| {
Expand All @@ -163,16 +186,18 @@
if attributes.with_serde {
struct_body
.push_parsed(format!(
"{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?).0,",
"{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<'_, {2}>>::borrow_decode(decoder)?).0,",
crate_name,
field
field,
decode_context,
))?;
} else {
struct_body
.push_parsed(format!(
"{1}: {0}::BorrowDecode::borrow_decode(decoder)?,",
"{1}: {0}::BorrowDecode::<'_, {2}>::borrow_decode(decoder)?,",
crate_name,
field
field,
decode_context,
))?;
}
}
Expand Down