1use crate::{
4 MAX_SCHEMA_FRAGMENT_BYTES, MAX_SCHEMA_PROPOSAL_BYTES, SchemaContractError, SchemaFragment,
5 SchemaProposal,
6};
7
8pub fn encode_schema_fragment(fragment: &SchemaFragment) -> Result<Vec<u8>, SchemaContractError> {
15 fragment.validate()?;
16 let bytes = candid::encode_one(fragment).map_err(|_| SchemaContractError::Encode)?;
17 enforce_encoded_bound(bytes, MAX_SCHEMA_FRAGMENT_BYTES)
18}
19
20pub fn decode_schema_fragment(bytes: &[u8]) -> Result<SchemaFragment, SchemaContractError> {
26 ensure_input_bound(bytes, MAX_SCHEMA_FRAGMENT_BYTES)?;
27 let fragment =
28 candid::decode_one::<SchemaFragment>(bytes).map_err(|_| SchemaContractError::Decode)?;
29 fragment.validate()?;
30 let canonical = encode_schema_fragment(&fragment)?;
31 if canonical != bytes {
32 return Err(SchemaContractError::NonCanonical);
33 }
34 Ok(fragment)
35}
36
37pub fn encode_schema_proposal(proposal: &SchemaProposal) -> Result<Vec<u8>, SchemaContractError> {
44 proposal.validate_current()?;
45 let bytes = candid::encode_one(proposal).map_err(|_| SchemaContractError::Encode)?;
46 enforce_encoded_bound(bytes, MAX_SCHEMA_PROPOSAL_BYTES)
47}
48
49pub fn decode_schema_proposal(bytes: &[u8]) -> Result<SchemaProposal, SchemaContractError> {
56 ensure_input_bound(bytes, MAX_SCHEMA_PROPOSAL_BYTES)?;
57 let proposal =
58 candid::decode_one::<SchemaProposal>(bytes).map_err(|_| SchemaContractError::Decode)?;
59 proposal.validate_current()?;
60 let canonical = encode_schema_proposal(&proposal)?;
61 if canonical != bytes {
62 return Err(SchemaContractError::NonCanonical);
63 }
64 Ok(proposal)
65}
66
67const fn ensure_input_bound(bytes: &[u8], max: usize) -> Result<(), SchemaContractError> {
68 if bytes.len() > max {
69 return Err(SchemaContractError::EncodedTooLarge {
70 len: bytes.len(),
71 max,
72 });
73 }
74 Ok(())
75}
76
77fn enforce_encoded_bound(bytes: Vec<u8>, max: usize) -> Result<Vec<u8>, SchemaContractError> {
78 ensure_input_bound(&bytes, max)?;
79 Ok(bytes)
80}