Skip to content

Commit

Permalink
feat: encode and don't consume the value (#593)
Browse files Browse the repository at this point in the history
`ArgumentEncoder` now have an extra `encode_ref()` method which takes
`&self` instead of `self`.
Calling `encode_ref()` won't consume the value.

The utils functions `write_args_ref()` and `encode_args_ref()` are also
added.

This change is required in dfinity/cdk-rs#551.

We will need to make a patch release of candid once this is approved.
  • Loading branch information
lwshang authored Jan 22, 2025
1 parent 32a6a6b commit f7269bc
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@

# Changelog

## 2025-01-22

### Candid 0.10.13

* Add `ArgumentEncoder::encode_ref`, `utils::{write_args, encode_args}` that don't consume the value when encoding.

## 2025-01-15

### Candid 0.10.12
Expand Down
2 changes: 1 addition & 1 deletion rust/candid/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "candid"
version = "0.10.12"
version = "0.10.13"
edition = "2021"
rust-version.workspace = true
authors = ["DFINITY Team"]
Expand Down
60 changes: 59 additions & 1 deletion rust/candid/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,29 @@ pub fn write_args<Tuple: ArgumentEncoder, Writer: std::io::Write>(
ser.serialize(writer)
}

/// Serialize an encoding of a tuple and write it to a `Write` buffer.
///
/// ```
/// # use candid::Decode;
/// # use candid::utils::write_args_ref;
/// let golden1 = 1u64;
/// let golden2 = "hello";
/// let mut buffer = Vec::new();
/// write_args_ref(&mut buffer, &(golden1, golden2)).unwrap();
///
/// let (value1, value2) = Decode!(&buffer, u64, String).unwrap();
/// assert_eq!(golden1, value1);
/// assert_eq!(golden2, value2);
/// ```
pub fn write_args_ref<Tuple: ArgumentEncoder, Writer: std::io::Write>(
writer: &mut Writer,
arguments: &Tuple,
) -> Result<()> {
let mut ser = IDLBuilder::new();
arguments.encode_ref(&mut ser)?;
ser.serialize(writer)
}

/// Serialize an encoding of a tuple to a vector of bytes.
///
/// ```
Expand All @@ -213,6 +236,25 @@ pub fn encode_args<Tuple: ArgumentEncoder>(arguments: Tuple) -> Result<Vec<u8>>
Ok(result)
}

/// Serialize an encoding of a tuple to a vector of bytes.
///
/// ```
/// # use candid::Decode;
/// # use candid::utils::encode_args_ref;
/// let golden1 = 1u64;
/// let golden2 = "hello";
/// let buffer = encode_args_ref(&(golden1, golden2)).unwrap();
///
/// let (value1, value2) = Decode!(&buffer, u64, String).unwrap();
/// assert_eq!(golden1, value1);
/// assert_eq!(golden2, value2);
/// ```
pub fn encode_args_ref<Tuple: ArgumentEncoder>(arguments: &Tuple) -> Result<Vec<u8>> {
let mut result = Vec::new();
write_args_ref(&mut result, arguments)?;
Ok(result)
}

/// Serialize a single value to a vector of bytes.
///
/// ```
Expand Down Expand Up @@ -245,11 +287,18 @@ impl<'a> ArgumentDecoder<'a> for () {
pub trait ArgumentEncoder {
/// Encode a value of type [Self].
fn encode(self, ser: &mut IDLBuilder) -> Result<()>;

/// Encode a reference value of type [Self].
fn encode_ref(&self, ser: &mut IDLBuilder) -> Result<()>;
}

/// Decode an empty tuple.
impl ArgumentEncoder for () {
fn encode(self, _de: &mut IDLBuilder) -> Result<()> {
fn encode(self, _ser: &mut IDLBuilder) -> Result<()> {
Ok(())
}

fn encode_ref(&self, _ser: &mut IDLBuilder) -> Result<()> {
Ok(())
}
}
Expand Down Expand Up @@ -287,6 +336,15 @@ macro_rules! encode_impl {

Ok(())
}

fn encode_ref(&self, ser: &mut IDLBuilder) -> Result<()> {
let ( $( $id, )* ) = self;
$(
ser.arg(&$id)?;
)*

Ok(())
}
}
}
}
Expand Down

0 comments on commit f7269bc

Please sign in to comment.