Skip to content

Commit

Permalink
add arbitrary for principal
Browse files Browse the repository at this point in the history
  • Loading branch information
venkkatesh-sekar committed Oct 31, 2023
1 parent 9c64865 commit c59d010
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/candid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ bignum = ["num-bigint", "num-traits"]
value = ["bignum"]
printer = ["pretty"]
default = ["serde_bytes", "printer", "bignum"]
all = ["default", "value"]
all = ["default", "value", "ic_principal/arbitrary"]

[[test]]
name = "types"
Expand Down
5 changes: 5 additions & 0 deletions rust/ic_principal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ optional = true
version = "0.11.5"
optional = true

[dependencies.arbitrary]
version = "1.0"
optional = true

[features]
# Default features include serde support.
default = ['serde', 'serde_bytes']
arbitrary = ['default', 'dep:arbitrary']
28 changes: 28 additions & 0 deletions rust/ic_principal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use std::convert::TryFrom;
use std::fmt::Write;
use thiserror::Error;

#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Result as ArbitraryResult, Unstructured};

/// An error happened while encoding, decoding or serializing a [`Principal`].
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand Down Expand Up @@ -358,3 +361,28 @@ impl<'de> serde::Deserialize<'de> for Principal {
}
}
}

#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for Principal {
fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult<Self> {
let principal = match u8::arbitrary(u)? {
u8::MAX => Principal::management_canister(),
254u8 => Principal::anonymous(),
_ => {
let length: usize = u.int_in_range(1..=Principal::MAX_LENGTH_IN_BYTES)?;
let mut result: Vec<u8> = Vec::with_capacity(length);
for _ in 0..length {
result.push(u8::arbitrary(u)?);
}
// non-anonymous principal cannot have type ANONYMOUS
// adapt by changing the last byte.
let last = result.last_mut().unwrap();
if *last == 4_u8 {
*last = u8::MAX
}
Principal::try_from(&result[..]).unwrap()
}
};
Ok(principal)
}
}

0 comments on commit c59d010

Please sign in to comment.