Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(builtins): json.obj_pairs, json.puts_pairs to build JSON objects from array of pairs #1434

Merged
merged 11 commits into from
Feb 2, 2023
6 changes: 2 additions & 4 deletions crates/json-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
unreachable_patterns
)]

use std::fmt::Display;

use serde_json::Value as JValue;

pub mod base64_serde;
Expand All @@ -48,6 +46,6 @@ pub fn into_array(v: JValue) -> Option<Vec<JValue>> {
}

/// Converts an error into IValue::String
pub fn err_as_value<E: Display>(err: E) -> JValue {
JValue::String(format!("Error: {err}"))
pub fn err_as_value<E: core::fmt::Debug>(err: E) -> JValue {
JValue::String(format!("Error: {err:?}"))
}
110 changes: 1 addition & 109 deletions crates/libp2p/src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,75 +39,10 @@ pub mod peerid_serializer {
}
}

// waiting for https://github.com/serde-rs/serde/issues/723 that will make UX better
pub mod provider_serializer {
use libp2p::{core::Multiaddr, PeerId};
use serde::{
de::{SeqAccess, Visitor},
ser::SerializeSeq,
Deserializer, Serializer,
};
use std::{fmt, str::FromStr};

pub fn serialize<S>(value: &[(Multiaddr, PeerId)], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(2 * value.len()))?;
for (multiaddr, peerid) in value {
seq.serialize_element(multiaddr)?;
seq.serialize_element(&peerid.to_base58())?;
}
seq.end()
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<(Multiaddr, PeerId)>, D::Error>
where
D: Deserializer<'de>,
{
struct VecVisitor;
impl<'de> Visitor<'de> for VecVisitor {
type Value = Vec<(Multiaddr, PeerId)>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("[Multiaddr, PeerId]")
}

fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut vec = Vec::new();

let mut raw_multiaddr = seq.next_element::<Multiaddr>()?;
while raw_multiaddr.is_some() {
let multiaddr = raw_multiaddr.unwrap();
let peer_id_bytes = seq.next_element::<String>()?;

if let Some(peer_id) = peer_id_bytes {
let peer_id = PeerId::from_str(&peer_id).map_err(|e| {
serde::de::Error::custom(format!(
"peer id deserialization failed for {e:?}"
))
})?;
vec.push((multiaddr, peer_id));
} else {
// Multiaddr deserialization's been successfull, but PeerId hasn't - return a error
return Err(serde::de::Error::custom("failed to deserialize PeerId"));
}

raw_multiaddr = seq.next_element::<Multiaddr>()?;
}

Ok(vec)
}
}

deserializer.deserialize_seq(VecVisitor {})
}
}

#[cfg(test)]
mod tests {
use crate::RandomPeerId;
use libp2p::{core::Multiaddr, PeerId};
use libp2p::PeerId;
use serde::{Deserialize, Serialize};
use std::str::FromStr;

Expand Down Expand Up @@ -180,47 +115,4 @@ mod tests {
);
assert_eq!(deserialized_test.unwrap(), test);
}

#[test]
fn providers() {
use super::provider_serializer;
use std::net::Ipv4Addr;

#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
struct Test {
#[serde(with = "provider_serializer")]
providers: Vec<(Multiaddr, PeerId)>,
}

let mut providers = Vec::new();
let mut test_peer_ids = Vec::new();
providers.push((
Multiaddr::from(Ipv4Addr::new(0, 0, 0, 0)),
PeerId::from_str("QmY28NSCefB532XbERtnKHadexGuNzAfYnh5fJk6qhLsSi").unwrap(),
));

for i in 1..=255 {
let peer_id = RandomPeerId::random();

providers.push((Multiaddr::from(Ipv4Addr::new(i, i, i, i)), peer_id));
test_peer_ids.push(peer_id);
}

let test = Test { providers };

let serialized_test = serde_json::to_value(test.clone());
assert!(
serialized_test.is_ok(),
"failed to serialize test struct: {}",
serialized_test.err().unwrap()
);

let deserialized_test = serde_json::from_value::<Test>(serialized_test.unwrap());
assert!(
deserialized_test.is_ok(),
"failed to deserialize test struct: {}",
deserialized_test.err().unwrap()
);
assert_eq!(deserialized_test.unwrap(), test);
}
}
5 changes: 5 additions & 0 deletions crates/particle-args/src/args_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use json_utils::err_as_value;

use eyre::Report;
use serde_json::{json, Value as JValue};
use std::borrow::Cow;
use std::fmt::{Display, Formatter};
Expand Down Expand Up @@ -66,6 +67,10 @@ impl JError {
pub fn new(msg: impl AsRef<str>) -> Self {
Self(json!(msg.as_ref()))
}

pub fn from_eyre(err: Report) -> Self {
JError(err_as_value(err))
}
}

impl From<JError> for JValue {
Expand Down
4 changes: 4 additions & 0 deletions particle-builtins/src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ where
("json", "puts") => wrap(json::puts(args)),
("json", "parse") => unary(args, |s: String| -> R<JValue, _> { json::parse(&s) }),
("json", "stringify") => unary(args, |v: JValue| -> R<String, _> { Ok(json::stringify(v)) }),
("json", "obj_pairs") => unary(args, |vs: Vec<(String, JValue)>| -> R<JValue, _> { json::obj_from_pairs(vs) }),
("json", "puts_pairs") => binary(args, |obj: JValue, vs: Vec<(String, JValue)>| -> R<JValue, _> { json::puts_from_pairs(obj, vs) }),

("run-console", "print") => wrap_unit(Ok(log::debug!(target: "run-console", "{}", json!(args.function_args)))),
folex marked this conversation as resolved.
Show resolved Hide resolved

_ => FunctionOutcome::NotDefined { args, params: particle },
}
Expand Down
43 changes: 38 additions & 5 deletions particle-builtins/src/json.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use eyre::eyre;
use eyre::{eyre, Context};
use particle_args::{Args, JError};
use serde_json::Value as JValue;

fn insert_pairs(
fn obj_from_iter(
mut object: serde_json::Map<String, JValue>,
args: &mut impl Iterator<Item = JValue>,
) -> Result<serde_json::Map<String, JValue>, JError> {
Expand All @@ -29,11 +29,26 @@ fn insert_pairs(
pub fn obj(args: Args) -> Result<JValue, JError> {
let mut args = args.function_args.into_iter();

let object = insert_pairs(<_>::default(), &mut args)?;
let object = obj_from_iter(<_>::default(), &mut args)?;

Ok(JValue::Object(object))
}

/// Constructs a JSON object from a list of key value pairs.
pub fn obj_from_pairs(
values: impl IntoIterator<Item = (String, JValue)>,
) -> Result<JValue, JError> {
let map = values.into_iter().fold(
<serde_json::Map<String, JValue>>::default(),
|mut acc, (k, v)| {
acc.insert(k, v);
acc
},
);

Ok(JValue::Object(map))
}

/// Inserts a value into a JSON object
pub fn put(args: Args) -> Result<JValue, JError> {
let mut args = args.function_args.into_iter();
Expand All @@ -51,13 +66,31 @@ pub fn puts(args: Args) -> Result<JValue, JError> {
let mut args = args.function_args.into_iter();
let object = Args::next("object", &mut args)?;

let object = insert_pairs(object, &mut args)?;
let object = obj_from_iter(object, &mut args)?;

Ok(JValue::Object(object))
}

/// Inserts list of key value pairs into an object.
pub fn puts_from_pairs(
object: JValue,
values: impl IntoIterator<Item = (String, JValue)>,
) -> Result<JValue, JError> {
if let JValue::Object(map) = object {
let map = values.into_iter().fold(map, |mut acc, (k, v)| {
acc.insert(k, v);
acc
});
Ok(JValue::Object(map))
} else {
Err(JError::new(format!("expected json object, got {object}")))
}
}

pub fn parse(json: &str) -> Result<JValue, JError> {
serde_json::from_str(json).map_err(Into::into)
serde_json::from_str(json)
.context(format!("error parsing json {json}"))
.map_err(JError::from_eyre)
}

pub fn stringify(value: JValue) -> String {
Expand Down