Skip to content

Commit

Permalink
Add 'Any' type for JSON serializable types
Browse files Browse the repository at this point in the history
  • Loading branch information
KendallWeihe committed Apr 24, 2024
1 parent b7ac054 commit 169abde
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 0 deletions.
1 change: 1 addition & 0 deletions bindings/uniffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ repository.workspace = true
license-file.workspace = true

[dependencies]
any = { path = "../../crates/any" }
credentials = { path = "../../crates/credentials" }
crypto = { path = "../../crates/crypto" }
dids = { path = "../../crates/dids" }
Expand Down
1 change: 1 addition & 0 deletions bindings/uniffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ::any::{Any, AnyError};
use ::credentials::vc::{verify_vcjwt, CredentialError, CredentialSubject, VerifiableCredential};
use ::crypto::Curve;
use ::dids::{
Expand Down
10 changes: 10 additions & 0 deletions bindings/uniffi/src/web5.udl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ namespace web5 {
VerifiableCredential verify_vcjwt([ByRef] string jwt);
};

[Error]
enum AnyError {
"SerdeError",
};

interface Any {
[Name=from_json_string, Throws=AnyError]
constructor(string json_string);
};

[Error]
enum KeyError {
"KeyGenerationFailed",
Expand Down
12 changes: 12 additions & 0 deletions crates/any/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "any"
version = "0.1.0"
edition = "2021"
homepage.workspace = true
repository.workspace = true
license-file.workspace = true

[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
127 changes: 127 additions & 0 deletions crates/any/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;

#[derive(thiserror::Error, Debug)]
pub enum AnyError {
#[error(transparent)]
SerdeError(#[from] serde_json::Error),
}

#[derive(Debug, Default, Clone)]
pub struct Any {
pub value: Value,
}

impl Serialize for Any {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.value.serialize(serializer)
}
}

impl<'de> Deserialize<'de> for Any {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Value::deserialize(deserializer).map(|value| Any { value })
}
}

impl Any {
pub fn from_json_string(json_string: String) -> Result<Self, AnyError> {
let value: Value = serde_json::from_str(&json_string)?;
Ok(Self { value })
}

pub fn from_generic<T: Serialize + DeserializeOwned>(any: T) -> Result<Self, AnyError> {
let json_str = serde_json::to_string(&any)?;
let value = serde_json::from_str(&json_str)?;
Ok(Self { value })
}
}

#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;

#[test]
fn test_serialize_simple_values() {
let any = Any {
value: json!("hello"),
};
let serialized = serde_json::to_string(&any).unwrap();
assert_eq!(serialized, "\"hello\"");
}

#[test]
fn test_serialize_complex_object() {
let any = Any {
value: json!({"key": "value", "number": 10}),
};
let serialized = serde_json::to_string(&any).unwrap();
assert_eq!(serialized, "{\"key\":\"value\",\"number\":10}");
}

#[test]
fn test_deserialize_simple_values() {
let json_str = "\"hello\"";
let any: Any = serde_json::from_str(json_str).unwrap();
assert_eq!(any.value, json!("hello"));
}

#[test]
fn test_deserialize_complex_object() {
let json_str = "{\"key\":\"value\",\"number\":10}";
let any: Any = serde_json::from_str(json_str).unwrap();
assert_eq!(any.value, json!({"key": "value", "number": 10}));
}

#[test]
fn test_from_json_string_error_handling() {
let json_str = "not a valid json";
let result = Any::from_json_string(json_str.to_string());
assert!(result.is_err());
}

#[test]
fn test_from_generic_conversion() {
let data = vec![1, 2, 3];
let any = Any::from_generic(data).unwrap();
assert_eq!(any.value, json!([1, 2, 3]));
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct TestStruct {
id: u32,
name: String,
}

#[test]
fn test_serialize_custom_struct() {
let test_struct = TestStruct {
id: 123,
name: "Alice".to_string(),
};
let any = Any::from_generic(test_struct).unwrap();
let serialized = serde_json::to_string(&any).unwrap();
assert_eq!(serialized, "{\"id\":123,\"name\":\"Alice\"}");
}

#[test]
fn test_deserialize_custom_struct() {
let json_str = "{\"id\":123,\"name\":\"Alice\"}";
let any: Any = serde_json::from_str(json_str).unwrap();
let deserialized: TestStruct = serde_json::from_value(any.value).unwrap();
assert_eq!(
deserialized,
TestStruct {
id: 123,
name: "Alice".to_string()
}
);
}
}
3 changes: 3 additions & 0 deletions web5-rs.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
{
"path": "examples"
},
{
"path": "crates/any"
},
{
"path": "crates/credentials"
},
Expand Down

0 comments on commit 169abde

Please sign in to comment.