From f216c74cc1130ebb1654ab132e77994911f9eb34 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 14 Feb 2024 00:28:12 +0100 Subject: [PATCH] feat: Add serialization traits to Status (#499) --- CHANGELOG.md | 1 + ic-agent/Cargo.toml | 1 + ic-agent/src/agent/status.rs | 49 ++++++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c852290..777b354a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Changed the return type of `stored_chunks` to a struct. * Added a prime256v1-based `Identity` impl to complement the ed25519 and secp256k1 `Identity` impls. +* Added serde and candid serialization traits to the `Status` type. ## [0.32.0] - 2024-01-18 diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index 9af39a73..91f92c1a 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -76,6 +76,7 @@ web-sys = { version = "0.3", features = ["Window"], optional = true } [dev-dependencies] serde_json = "1.0.79" +candid = { workspace = true, features = ["value"]} [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] tokio = { version = "1.24.2", features = ["full"] } diff --git a/ic-agent/src/agent/status.rs b/ic-agent/src/agent/status.rs index ef49be0b..e54ea251 100644 --- a/ic-agent/src/agent/status.rs +++ b/ic-agent/src/agent/status.rs @@ -1,11 +1,15 @@ //! Types for interacting with the status endpoint of a replica. See [`Status`] for details. +use candid::{CandidType, Deserialize}; +use serde::Serialize; use std::{collections::BTreeMap, fmt::Debug}; /// Value returned by the status endpoint of a replica. This is a loose mapping to CBOR values. /// Because the agent should not return [`serde_cbor::Value`] directly across API boundaries, /// we reimplement it as [`Value`] here. -#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash)] +#[derive( + Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, CandidType, Serialize, Deserialize, +)] pub enum Value { /// See [`Null`](serde_cbor::Value::Null). Null, @@ -40,7 +44,7 @@ impl std::fmt::Display for Value { /// The structure returned by [`super::Agent::status`], containing the information returned /// by the status endpoint of a replica. -#[derive(Debug, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Debug, Ord, PartialOrd, PartialEq, Eq, CandidType, Deserialize, Serialize)] pub struct Status { /// Optional. The precise git revision of the Internet Computer Protocol implementation. pub impl_version: Option, @@ -55,6 +59,47 @@ pub struct Status { pub values: BTreeMap>, } +#[test] +fn can_serilaize_status_as_json() { + let status = Status { + impl_version: None, + replica_health_status: None, + root_key: None, + values: BTreeMap::new(), + }; + let expected_json = + r#"{"impl_version":null,"replica_health_status":null,"root_key":null,"values":{}}"#; + let actual_json = serde_json::to_string(&status).expect("Failed to serialize as JSON"); + assert_eq!(expected_json, actual_json); +} +#[test] +fn can_serialize_status_as_idl() { + use candid::types::value::IDLValue; + use candid::{Encode, IDLArgs, Result as CandidResult, TypeEnv}; + let status = Status { + impl_version: Some("Foo".to_string()), + replica_health_status: None, + root_key: None, + values: BTreeMap::new(), + }; + // Expresses data as IDLValue. Then use .to_string() to convert to text-form candid. + // TODO: This function has been added to the Candid library and will be available in the next + // release. Then, this definition here can be deleted. + pub fn try_from_candid_type(data: &T) -> CandidResult + where + T: CandidType, + { + let blob = Encode!(data)?; + let args = IDLArgs::from_bytes_with_types(&blob, &TypeEnv::default(), &[T::ty()])?; + Ok(args.args[0].clone()) + } + let expected_idl = "record {\n values = vec {};\n replica_health_status = null;\n impl_version = opt \"Foo\";\n root_key = null;\n}"; + let actual_idl = try_from_candid_type(&status) + .expect("Failed to convert to idl") + .to_string(); + assert_eq!(expected_idl, actual_idl); +} + impl std::fmt::Display for Status { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("{\n")?;