bounded_vec: Avoid unnecessary allocation when decoding#713
Conversation
KiChjang
left a comment
There was a problem hiding this comment.
Also probably requires a version bump for substrate to pick up the changes.
Should I do that in this PR? Also, I'll try to get to |
ggwpez
left a comment
There was a problem hiding this comment.
Should I do that in this PR?
You can also do it in another PR, just thought it would fit in here 😄
|
As the crate is currently lacking test, I would be happy if this pr could start with this ;) We could ensure that we don't consume more data than the compact length. |
|
@bkchr There are tests, including for that case -- see |
|
This PR is already approved, but would like a quick re-approval from someone (to sanity check the last two commits). :) |
Dump idea: Just use |
This should do it. Also some easy tests ensuring that
Sorry 🙈 |
| return Err("BoundedBTreeMap exceeds its limit".into()) | ||
| } | ||
| input.descend_ref()?; | ||
| let inner = Result::from_iter((0..len).map(|_| Decode::decode(input)))?; |
There was a problem hiding this comment.
No idea if rust handles this in the most efficient way, otherwise we should maybe pre-allocate as optimization.
There was a problem hiding this comment.
I mean this is now discusable with the bound, but for the normal BTreeMap we don't have done this as someone could send you a fake encoded BTreeMap that pretends to be u32::Max in size and then maybe leading to some OOM.
There was a problem hiding this comment.
Interesting, would have to compile with optimizations and see. At any rate, I don't want to deviate too much from the standard Decode for the unbounded types, at least in this PR.
There was a problem hiding this comment.
Is this just another way of calling collect?
| let inner = Result::from_iter((0..len).map(|_| Decode::decode(input)))?; | |
| let inner = (0..len).map(|_| Decode::decode(input)).collect::<Result<Vec<_>, codec::Error>>()?; |
There was a problem hiding this comment.
Yes, I think it is. http://doc.rust-lang.org/1.66.1/std/result/enum.Result.html#method.from_iter
Currently this impl is the same as the unbounded version, apart from the length check. I think it should be kept the same unless there's a good reason not to.
bkchr
left a comment
There was a problem hiding this comment.
Ty! But let us use the same derives everywhere.
| return Err("BoundedBTreeMap exceeds its limit".into()) | ||
| } | ||
| input.descend_ref()?; | ||
| let inner = Result::from_iter((0..len).map(|_| Decode::decode(input)))?; |
| /// | ||
| /// Unlike a standard `BTreeMap`, there is an enforced upper limit to the number of items in the | ||
| /// map. All internal operations ensure this bound is respected. | ||
| #[cfg_attr(feature = "std", derive(Hash))] |
There was a problem hiding this comment.
| #[cfg_attr(feature = "std", derive(Hash))] | |
| #[cfg_attr(feature = "std", derive(Hash, serde::Serialize, serde::Deserialize), serde(transparent))] |
There was a problem hiding this comment.
I'm not sure about deriving these; Deserialize would need a custom impl to add bounds checks, like we do now with BoundedVec. And the custom impl looks annoying to implement, so I'm thinking we don't add it until there's actually a need for it.
There was a problem hiding this comment.
@bkchr I'm going to go ahead and merge -- these derives can be a follow-up if we really want them.
| /// | ||
| /// Unlike a standard `BTreeSet`, there is an enforced upper limit to the number of items in the | ||
| /// set. All internal operations ensure this bound is respected. | ||
| #[cfg_attr(feature = "std", derive(Hash))] |
There was a problem hiding this comment.
| #[cfg_attr(feature = "std", derive(Hash))] | |
| #[cfg_attr(feature = "std", derive(Hash, serde::Serialize, serde::Deserialize), serde(transparent))] |
| /// As the name suggests, the length of the queue is always bounded. All internal operations ensure | ||
| /// this bound is respected. | ||
| #[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] | ||
| #[cfg_attr(feature = "std", derive(Hash, Serialize), serde(transparent))] |
There was a problem hiding this comment.
| #[cfg_attr(feature = "std", derive(Hash, Serialize), serde(transparent))] | |
| #[cfg_attr(feature = "std", derive(Hash, serde::Serialize, serde::Deserialize), serde(transparent))] |
|
@KiChjang Looks like I'm not able to publish |
|
I've added the core-devs team as the owner for the crate on crates.io. |
Needed for paritytech/polkadot#6603. See paritytech/polkadot#6603 (comment):