Skip to content

Commit c8a42f7

Browse files
ZoeyRbranchseer
andauthored
Decode context (#749)
Add an optional context for decoding allowing additional data to be passed to decoded structs. --------- Co-authored-by: branchseer <[email protected]>
1 parent 56da696 commit c8a42f7

24 files changed

+774
-378
lines changed

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ unty = "0.0.3"
3737

3838
# Used for tests
3939
[dev-dependencies]
40+
ouroboros = "0.18.3"
4041
serde_derive = "1.0"
4142
serde_json = { version = "1.0", default-features = false }
4243
tempfile = "3.2"
@@ -47,6 +48,7 @@ chrono = { version = "0.4", features = ["serde"] }
4748
glam = { version = "0.25", features = ["serde"] }
4849
bincode_1 = { version = "1.3", package = "bincode" }
4950
serde = { version = "1.0", features = ["derive"] }
51+
bumpalo = { version = "3.16.0", features = ["collections"] }
5052

5153
[[bench]]
5254
name = "varint"

compatibility/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mod sway;
1111
pub fn test_same_with_config<T, C, O>(t: &T, bincode_1_options: O, bincode_2_config: C)
1212
where
1313
T: bincode_2::Encode
14-
+ bincode_2::Decode
14+
+ bincode_2::Decode<()>
1515
+ serde::Serialize
1616
+ serde::de::DeserializeOwned
1717
+ core::fmt::Debug
@@ -60,7 +60,7 @@ where
6060
pub fn test_same<T>(t: T)
6161
where
6262
T: bincode_2::Encode
63-
+ bincode_2::Decode
63+
+ bincode_2::Decode<()>
6464
+ serde::Serialize
6565
+ serde::de::DeserializeOwned
6666
+ core::fmt::Debug

derive/src/attribute.rs

+11
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub struct ContainerAttributes {
55
pub crate_name: String,
66
pub bounds: Option<(String, Literal)>,
77
pub decode_bounds: Option<(String, Literal)>,
8+
pub decode_context: Option<(String, Literal)>,
89
pub borrow_decode_bounds: Option<(String, Literal)>,
910
pub encode_bounds: Option<(String, Literal)>,
1011
}
@@ -15,6 +16,7 @@ impl Default for ContainerAttributes {
1516
crate_name: "::bincode".to_string(),
1617
bounds: None,
1718
decode_bounds: None,
19+
decode_context: None,
1820
encode_bounds: None,
1921
borrow_decode_bounds: None,
2022
}
@@ -56,6 +58,15 @@ impl FromAttribute for ContainerAttributes {
5658
return Err(Error::custom_at("Should be a literal str", val.span()));
5759
}
5860
}
61+
ParsedAttribute::Property(key, val) if key.to_string() == "decode_context" => {
62+
let val_string = val.to_string();
63+
if val_string.starts_with('"') && val_string.ends_with('"') {
64+
result.decode_context =
65+
Some((val_string[1..val_string.len() - 1].to_string(), val));
66+
} else {
67+
return Err(Error::custom_at("Should be a literal str", val.span()));
68+
}
69+
}
5970
ParsedAttribute::Property(key, val) if key.to_string() == "encode_bounds" => {
6071
let val_string = val.to_string();
6172
if val_string.starts_with('"') && val_string.ends_with('"') {

derive/src/derive_enum.rs

+37-13
Original file line numberDiff line numberDiff line change
@@ -219,25 +219,36 @@ impl DeriveEnum {
219219
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
220220
let crate_name = self.attributes.crate_name.as_str();
221221

222+
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
223+
decode_context.as_str()
224+
} else {
225+
"__Context"
226+
};
222227
// Remember to keep this mostly in sync with generate_borrow_decode
223228

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

226-
generator
227-
.impl_for(format!("{}::Decode", crate_name))
231+
let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name));
232+
233+
if self.attributes.decode_context.is_none() {
234+
impl_for = impl_for.with_impl_generics(["__Context"]);
235+
}
236+
237+
impl_for
238+
.with_trait_generics([decode_context])
228239
.modify_generic_constraints(|generics, where_constraints| {
229240
if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
230241
where_constraints.clear();
231242
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
232243
} else {
233244
for g in generics.iter_generics() {
234-
where_constraints.push_constraint(g, format!("{}::Decode", crate_name))?;
245+
where_constraints.push_constraint(g, format!("{}::Decode<__Context>", crate_name))?;
235246
}
236247
}
237248
Ok(())
238249
})?
239250
.generate_fn("decode")
240-
.with_generic_deps("__D", [format!("{}::de::Decoder", crate_name)])
251+
.with_generic_deps("__D", [format!("{}::de::Decoder<Context = {}>", crate_name, decode_context)])
241252
.with_arg("decoder", "&mut __D")
242253
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
243254
.body(|fn_builder| {
@@ -249,7 +260,7 @@ impl DeriveEnum {
249260
} else {
250261
fn_builder
251262
.push_parsed(format!(
252-
"let variant_index = <u32 as {}::Decode>::decode(decoder)?;",
263+
"let variant_index = <u32 as {}::Decode::<__D::Context>>::decode(decoder)?;",
253264
crate_name
254265
))?;
255266
fn_builder.push_parsed("match variant_index")?;
@@ -286,13 +297,13 @@ impl DeriveEnum {
286297
if attributes.with_serde {
287298
variant_body
288299
.push_parsed(format!(
289-
"<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?.0,",
300+
"<{0}::serde::Compat<_> as {0}::Decode::<__D::Context>>::decode(decoder)?.0,",
290301
crate_name
291302
))?;
292303
} else {
293304
variant_body
294305
.push_parsed(format!(
295-
"{}::Decode::decode(decoder)?,",
306+
"{}::Decode::<__D::Context>::decode(decoder)?,",
296307
crate_name
297308
))?;
298309
}
@@ -318,17 +329,30 @@ impl DeriveEnum {
318329
pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
319330
let crate_name = &self.attributes.crate_name;
320331

332+
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
333+
decode_context.as_str()
334+
} else {
335+
"__Context"
336+
};
337+
321338
// Remember to keep this mostly in sync with generate_decode
322339
let enum_name = generator.target_name().to_string();
323340

324-
generator.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
341+
let mut impl_for = generator
342+
.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
343+
.with_trait_generics([decode_context]);
344+
if self.attributes.decode_context.is_none() {
345+
impl_for = impl_for.with_impl_generics(["__Context"]);
346+
}
347+
348+
impl_for
325349
.modify_generic_constraints(|generics, where_constraints| {
326350
if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
327351
where_constraints.clear();
328352
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
329353
} else {
330354
for g in generics.iter_generics() {
331-
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap();
355+
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap();
332356
}
333357
for lt in generics.iter_lifetimes() {
334358
where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?;
@@ -337,7 +361,7 @@ impl DeriveEnum {
337361
Ok(())
338362
})?
339363
.generate_fn("borrow_decode")
340-
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)])
364+
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Context = {}>", crate_name, decode_context)])
341365
.with_arg("decoder", "&mut __D")
342366
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
343367
.body(|fn_builder| {
@@ -348,7 +372,7 @@ impl DeriveEnum {
348372
))?;
349373
} else {
350374
fn_builder
351-
.push_parsed(format!("let variant_index = <u32 as {}::Decode>::decode(decoder)?;", crate_name))?;
375+
.push_parsed(format!("let variant_index = <u32 as {}::Decode::<__D::Context>>::decode(decoder)?;", crate_name))?;
352376
fn_builder.push_parsed("match variant_index")?;
353377
fn_builder.group(Delimiter::Brace, |variant_case| {
354378
for (mut variant_index, variant) in self.iter_fields() {
@@ -382,9 +406,9 @@ impl DeriveEnum {
382406
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
383407
if attributes.with_serde {
384408
variant_body
385-
.push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?.0,", crate_name))?;
409+
.push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<__D::Context>>::borrow_decode(decoder)?.0,", crate_name))?;
386410
} else {
387-
variant_body.push_parsed(format!("{}::BorrowDecode::borrow_decode(decoder)?,", crate_name))?;
411+
variant_body.push_parsed(format!("{}::BorrowDecode::<__D::Context>::borrow_decode(decoder)?,", crate_name))?;
388412
}
389413
}
390414
}

derive/src/derive_struct.rs

+38-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
use crate::attribute::{ContainerAttributes, FieldAttributes};
2-
use virtue::generate::Generator;
3-
use virtue::parse::Fields;
42
use virtue::prelude::*;
53

64
pub(crate) struct DeriveStruct {
@@ -67,22 +65,32 @@ impl DeriveStruct {
6765
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
6866
// Remember to keep this mostly in sync with generate_borrow_decode
6967
let crate_name = &self.attributes.crate_name;
68+
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
69+
decode_context.as_str()
70+
} else {
71+
"__Context"
72+
};
7073

71-
generator
72-
.impl_for(format!("{}::Decode", crate_name))
74+
let mut impl_for = generator.impl_for(format!("{}::Decode", crate_name));
75+
if self.attributes.decode_context.is_none() {
76+
impl_for = impl_for.with_impl_generics(["__Context"]);
77+
}
78+
79+
impl_for
80+
.with_trait_generics([decode_context])
7381
.modify_generic_constraints(|generics, where_constraints| {
7482
if let Some((bounds, lit)) = (self.attributes.decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
7583
where_constraints.clear();
7684
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
7785
} else {
7886
for g in generics.iter_generics() {
79-
where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap();
87+
where_constraints.push_constraint(g, format!("{}::Decode<{}>", crate_name, decode_context)).unwrap();
8088
}
8189
}
8290
Ok(())
8391
})?
8492
.generate_fn("decode")
85-
.with_generic_deps("__D", [format!("{}::de::Decoder", crate_name)])
93+
.with_generic_deps("__D", [format!("{}::de::Decoder<Context = {}>", crate_name, decode_context)])
8694
.with_arg("decoder", "&mut __D")
8795
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
8896
.body(|fn_body| {
@@ -103,9 +111,10 @@ impl DeriveStruct {
103111
if attributes.with_serde {
104112
struct_body
105113
.push_parsed(format!(
106-
"{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,",
114+
"{1}: (<{0}::serde::Compat<_> as {0}::Decode::<{2}>>::decode(decoder)?).0,",
107115
crate_name,
108-
field
116+
field,
117+
decode_context,
109118
))?;
110119
} else {
111120
struct_body
@@ -131,15 +140,27 @@ impl DeriveStruct {
131140
// Remember to keep this mostly in sync with generate_decode
132141
let crate_name = self.attributes.crate_name;
133142

134-
generator
143+
let decode_context = if let Some((decode_context, _)) = &self.attributes.decode_context {
144+
decode_context.as_str()
145+
} else {
146+
"__Context"
147+
};
148+
149+
let mut impl_for = generator
135150
.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])
151+
.with_trait_generics([decode_context]);
152+
if self.attributes.decode_context.is_none() {
153+
impl_for = impl_for.with_impl_generics(["__Context"]);
154+
}
155+
156+
impl_for
136157
.modify_generic_constraints(|generics, where_constraints| {
137158
if let Some((bounds, lit)) = (self.attributes.borrow_decode_bounds.as_ref()).or(self.attributes.bounds.as_ref()) {
138159
where_constraints.clear();
139160
where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?;
140161
} else {
141162
for g in generics.iter_generics() {
142-
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap();
163+
where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de, {}>", crate_name, decode_context)).unwrap();
143164
}
144165
for lt in generics.iter_lifetimes() {
145166
where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?;
@@ -148,7 +169,7 @@ impl DeriveStruct {
148169
Ok(())
149170
})?
150171
.generate_fn("borrow_decode")
151-
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)])
172+
.with_generic_deps("__D", [format!("{}::de::BorrowDecoder<'__de, Context = {}>", crate_name, decode_context)])
152173
.with_arg("decoder", "&mut __D")
153174
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
154175
.body(|fn_body| {
@@ -163,16 +184,18 @@ impl DeriveStruct {
163184
if attributes.with_serde {
164185
struct_body
165186
.push_parsed(format!(
166-
"{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?).0,",
187+
"{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode::<'_, {2}>>::borrow_decode(decoder)?).0,",
167188
crate_name,
168-
field
189+
field,
190+
decode_context,
169191
))?;
170192
} else {
171193
struct_body
172194
.push_parsed(format!(
173-
"{1}: {0}::BorrowDecode::borrow_decode(decoder)?,",
195+
"{1}: {0}::BorrowDecode::<'_, {2}>::borrow_decode(decoder)?,",
174196
crate_name,
175-
field
197+
field,
198+
decode_context,
176199
))?;
177200
}
178201
}

0 commit comments

Comments
 (0)