mirror of
https://git.asonix.dog/asonix/activitystreams.git
synced 2024-11-25 13:21:00 +00:00
Add 'closed' to Question
This commit is contained in:
parent
2f9532ad65
commit
f3d394d5d6
5 changed files with 383 additions and 9 deletions
|
@ -1,5 +1,10 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
# 0.7.0-alpha.17
|
||||||
|
- add `XsdBoolean` for `xsd:boolean` serde compatibility
|
||||||
|
- add `closed` field for `Question` (range Object | Link | xsd:datetime | xsd:boolean), and related
|
||||||
|
getters and setters
|
||||||
|
|
||||||
# 0.7.0-alpha.16
|
# 0.7.0-alpha.16
|
||||||
- implement `IntoIterator` for `&OneOrMany<T>` and `&mut OneOrMany<T>`
|
- implement `IntoIterator` for `&OneOrMany<T>` and `&mut OneOrMany<T>`
|
||||||
- add `check` function for verifying an IRI's authority
|
- add `check` function for verifying an IRI's authority
|
||||||
|
|
17
Cargo.toml
17
Cargo.toml
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "activitystreams"
|
name = "activitystreams"
|
||||||
description = "A set of core types and traits for activitystreams data"
|
description = "A set of core types and traits for activitystreams data"
|
||||||
version = "0.7.0-alpha.16"
|
version = "0.7.0-alpha.17"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["asonix <asonix@asonix.dog>"]
|
authors = ["asonix <asonix@asonix.dog>"]
|
||||||
repository = "https://git.asonix.dog/Aardwolf/activitystreams"
|
repository = "https://git.asonix.dog/Aardwolf/activitystreams"
|
||||||
|
@ -13,14 +13,17 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = ["activitystreams-ext", "activitystreams-kinds"]
|
||||||
"activitystreams-ext",
|
|
||||||
"activitystreams-kinds"
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
activitystreams-kinds = { version = "0.2.0", path = "./activitystreams-kinds/", default-features = false, features = ["iri-string"] }
|
activitystreams-kinds = { version = "0.2.0", path = "./activitystreams-kinds/", default-features = false, features = [
|
||||||
iri-string = { version = "0.5.0-beta.1", features = ["serde", "serde-std", "std"] }
|
"iri-string",
|
||||||
|
] }
|
||||||
|
iri-string = { version = "0.5.0-beta.1", features = [
|
||||||
|
"serde",
|
||||||
|
"serde-std",
|
||||||
|
"std",
|
||||||
|
] }
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
199
src/activity.rs
199
src/activity.rs
|
@ -25,14 +25,16 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
base::{AnyBase, AsBase, Base, Extends},
|
base::{AnyBase, AsBase, Base, Extends},
|
||||||
checked::CheckError,
|
checked::CheckError,
|
||||||
|
either::Either,
|
||||||
markers,
|
markers,
|
||||||
object::{ApObject, AsObject, Object},
|
object::{ApObject, AsObject, Object},
|
||||||
prelude::BaseExt,
|
prelude::BaseExt,
|
||||||
primitives::OneOrMany,
|
primitives::{OneOrMany, XsdBoolean, XsdDateTime},
|
||||||
unparsed::{Unparsed, UnparsedMut, UnparsedMutExt},
|
unparsed::{Unparsed, UnparsedMut, UnparsedMutExt},
|
||||||
};
|
};
|
||||||
use iri_string::types::IriString;
|
use iri_string::types::IriString;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
pub use activitystreams_kinds::activity as kind;
|
pub use activitystreams_kinds::activity as kind;
|
||||||
|
|
||||||
|
@ -1418,6 +1420,185 @@ pub trait QuestionExt: AsQuestion {
|
||||||
self.question_mut().any_of = None;
|
self.question_mut().any_of = None;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch the closed field for the current activity
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use activitystreams::activity::Question;
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
/// #
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
///
|
||||||
|
/// if let Some(closed) = question.closed() {
|
||||||
|
/// println!("{:?}", closed);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn closed(&self) -> Option<Either<&OneOrMany<AnyBase>, Either<OffsetDateTime, bool>>> {
|
||||||
|
self.question_ref().closed.as_ref().map(|either| {
|
||||||
|
either
|
||||||
|
.as_ref()
|
||||||
|
.map(|l| l, |r| r.as_ref().map(|l| *l.as_datetime(), |r| r.0))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the closed field for the current activity
|
||||||
|
///
|
||||||
|
/// This overwrites the contents of any_of
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # fn main() -> Result<(), anyhow::Error> {
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
/// # use activitystreams::{activity::Question, iri};
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
///
|
||||||
|
/// question.set_closed_base(iri!("https://example.com/one"));
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn set_closed_base<T>(&mut self, closed: T) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<AnyBase>,
|
||||||
|
{
|
||||||
|
self.question_mut().closed = Some(Either::Left(OneOrMany::from_one(closed.into())));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set many closed items for the current activity
|
||||||
|
///
|
||||||
|
/// This overwrites the contents of any_of
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # fn main() -> Result<(), anyhow::Error> {
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
/// # use activitystreams::{activity::Question, iri};
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
///
|
||||||
|
/// question.set_many_closed_bases(vec![
|
||||||
|
/// iri!("https://example.com/one"),
|
||||||
|
/// iri!("https://example.com/two"),
|
||||||
|
/// ]);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn set_many_closed_bases<I, T>(&mut self, closed: I) -> &mut Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
T: Into<AnyBase>,
|
||||||
|
{
|
||||||
|
let many = OneOrMany::from_many(closed.into_iter().map(|t| t.into()).collect());
|
||||||
|
self.question_mut().closed = Some(Either::Left(many));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the closed field as a date
|
||||||
|
///
|
||||||
|
/// This overwrites the contents of any_of
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # fn main() -> Result<(), anyhow::Error> {
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
/// # use activitystreams::{activity::Question, iri};
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
///
|
||||||
|
/// question.set_closed_date(time::OffsetDateTime::now_utc());
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn set_closed_date(&mut self, closed: OffsetDateTime) -> &mut Self {
|
||||||
|
self.question_mut().closed = Some(Either::Right(Either::Left(closed.into())));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the closed field as a boolean
|
||||||
|
///
|
||||||
|
/// This overwrites the contents of any_of
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # fn main() -> Result<(), anyhow::Error> {
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
/// # use activitystreams::{activity::Question, iri};
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
///
|
||||||
|
/// question.set_closed_bool(true);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn set_closed_bool(&mut self, closed: bool) -> &mut Self {
|
||||||
|
self.question_mut().closed = Some(Either::Right(Either::Right(closed.into())));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an object or link to the closed field
|
||||||
|
///
|
||||||
|
/// This overwrites the contents of any_of
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # fn main() -> Result<(), anyhow::Error> {
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
/// # use activitystreams::{activity::Question, iri};
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
///
|
||||||
|
/// question
|
||||||
|
/// .add_closed_base(iri!("https://example.com/one"))
|
||||||
|
/// .add_closed_base(iri!("https://example.com/two"));
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn add_closed_base<T>(&mut self, closed: T) -> &mut Self
|
||||||
|
where
|
||||||
|
T: Into<AnyBase>,
|
||||||
|
{
|
||||||
|
let one_or_many = match self.question_mut().closed.take() {
|
||||||
|
Some(Either::Left(mut one_or_many)) => {
|
||||||
|
one_or_many.add(closed.into());
|
||||||
|
one_or_many
|
||||||
|
}
|
||||||
|
_ => OneOrMany::from_one(closed.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.question_mut().closed = Some(Either::Left(one_or_many));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take the closed field from the current activity
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use activitystreams::activity::Question;
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
/// #
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
///
|
||||||
|
/// if let Some(closed) = question.take_closed() {
|
||||||
|
/// println!("{:?}", closed);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn take_closed(&mut self) -> Option<Either<OneOrMany<AnyBase>, Either<OffsetDateTime, bool>>> {
|
||||||
|
self.question_mut()
|
||||||
|
.closed
|
||||||
|
.take()
|
||||||
|
.map(|either| either.map(|l| l, |r| r.map(|date| date.into(), |b| b.into())))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the closed field from the current activity
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # fn main() -> Result<(), anyhow::Error> {
|
||||||
|
/// # use activitystreams::{activity::Question, iri};
|
||||||
|
/// # let mut question = Question::new();
|
||||||
|
/// # question.set_closed_bool(true);
|
||||||
|
/// #
|
||||||
|
/// use activitystreams::prelude::*;
|
||||||
|
///
|
||||||
|
/// assert!(question.closed().is_some());
|
||||||
|
/// question.delete_closed();
|
||||||
|
/// assert!(question.closed().is_none());
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
fn delete_closed(&mut self) -> &mut Self {
|
||||||
|
self.question_mut().closed = None;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates that the actor accepts the object.
|
/// Indicates that the actor accepts the object.
|
||||||
|
@ -1940,6 +2121,13 @@ pub struct Question {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
any_of: Option<OneOrMany<AnyBase>>,
|
any_of: Option<OneOrMany<AnyBase>>,
|
||||||
|
|
||||||
|
/// Indicates that a question has been closed, and answers are no longer accepted.
|
||||||
|
///
|
||||||
|
/// - Range: Object | Link | xsd:datetime | xsd:boolean
|
||||||
|
/// - Functional: false
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
closed: Option<Either<OneOrMany<AnyBase>, Either<XsdDateTime, XsdBoolean>>>,
|
||||||
|
|
||||||
/// base fields and unparsed json ends up here
|
/// base fields and unparsed json ends up here
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
inner: Activity<QuestionType>,
|
inner: Activity<QuestionType>,
|
||||||
|
@ -2619,6 +2807,7 @@ impl Question {
|
||||||
Question {
|
Question {
|
||||||
one_of: None,
|
one_of: None,
|
||||||
any_of: None,
|
any_of: None,
|
||||||
|
closed: None,
|
||||||
inner: Activity::new(),
|
inner: Activity::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2647,10 +2836,12 @@ impl Question {
|
||||||
|
|
||||||
let one_of = inner.remove("oneOf")?;
|
let one_of = inner.remove("oneOf")?;
|
||||||
let any_of = inner.remove("anyOf")?;
|
let any_of = inner.remove("anyOf")?;
|
||||||
|
let closed = inner.remove("closed")?;
|
||||||
|
|
||||||
Ok(Question {
|
Ok(Question {
|
||||||
one_of,
|
one_of,
|
||||||
any_of,
|
any_of,
|
||||||
|
closed,
|
||||||
inner,
|
inner,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2659,10 +2850,14 @@ impl Question {
|
||||||
let Question {
|
let Question {
|
||||||
one_of,
|
one_of,
|
||||||
any_of,
|
any_of,
|
||||||
|
closed,
|
||||||
mut inner,
|
mut inner,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
inner.insert("oneOf", one_of)?.insert("anyOf", any_of)?;
|
inner
|
||||||
|
.insert("oneOf", one_of)?
|
||||||
|
.insert("anyOf", any_of)?
|
||||||
|
.insert("closed", closed)?;
|
||||||
|
|
||||||
inner.retracting()
|
inner.retracting()
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ mod one_or_many;
|
||||||
mod rdf_lang_string;
|
mod rdf_lang_string;
|
||||||
mod serde_parse;
|
mod serde_parse;
|
||||||
mod unit;
|
mod unit;
|
||||||
|
mod xsd_boolean;
|
||||||
mod xsd_datetime;
|
mod xsd_datetime;
|
||||||
mod xsd_duration;
|
mod xsd_duration;
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ pub use self::{
|
||||||
one_or_many::OneOrMany,
|
one_or_many::OneOrMany,
|
||||||
rdf_lang_string::RdfLangString,
|
rdf_lang_string::RdfLangString,
|
||||||
unit::Unit,
|
unit::Unit,
|
||||||
|
xsd_boolean::XsdBoolean,
|
||||||
xsd_datetime::XsdDateTime,
|
xsd_datetime::XsdDateTime,
|
||||||
xsd_duration::{XsdDuration, XsdDurationError},
|
xsd_duration::{XsdDuration, XsdDurationError},
|
||||||
};
|
};
|
||||||
|
|
169
src/primitives/xsd_boolean.rs
Normal file
169
src/primitives/xsd_boolean.rs
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
use crate::either::Either;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
/// The type xsd:boolean represents logical yes/no values. The valid values for xsd:boolean are
|
||||||
|
/// true, false, 0, and 1. Values that are capitalized (e.g. TRUE) or abbreviated (e.g. T) are not
|
||||||
|
/// valid.
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub struct XsdBoolean(pub bool);
|
||||||
|
|
||||||
|
impl XsdBoolean {
|
||||||
|
/// Construct a new XsdBoolean
|
||||||
|
pub fn new(b: bool) -> Self {
|
||||||
|
Self(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retreive the inner bool
|
||||||
|
pub fn into_inner(self) -> bool {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<bool> for XsdBoolean {
|
||||||
|
fn eq(&self, other: &bool) -> bool {
|
||||||
|
self.0 == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<XsdBoolean> for bool {
|
||||||
|
fn eq(&self, other: &XsdBoolean) -> bool {
|
||||||
|
*self == other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for XsdBoolean {
|
||||||
|
type Target = bool;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for XsdBoolean {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<bool> for XsdBoolean {
|
||||||
|
fn as_ref(&self) -> &bool {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<bool> for XsdBoolean {
|
||||||
|
fn as_mut(&mut self) -> &mut bool {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for XsdBoolean {
|
||||||
|
fn from(b: bool) -> Self {
|
||||||
|
Self(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<XsdBoolean> for bool {
|
||||||
|
fn from(b: XsdBoolean) -> Self {
|
||||||
|
b.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for XsdBoolean {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let helper: Either<u8, bool> = Deserialize::<'de>::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
match helper {
|
||||||
|
Either::Left(u @ 0 | u @ 1) => Ok(XsdBoolean(u == 1)),
|
||||||
|
Either::Right(b) => Ok(XsdBoolean(b)),
|
||||||
|
_ => Err(serde::de::Error::custom("Invalid boolean")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for XsdBoolean {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
self.0.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::XsdBoolean;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||||
|
struct MyStruct {
|
||||||
|
field: XsdBoolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_bool() {
|
||||||
|
let json = r#"[{"field":true},{"field":false}]"#;
|
||||||
|
|
||||||
|
let structs: Vec<MyStruct> = serde_json::from_str(json).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(structs[0].field, true);
|
||||||
|
assert_eq!(structs[1].field, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_number() {
|
||||||
|
let json = r#"[{"field":1},{"field":0}]"#;
|
||||||
|
|
||||||
|
let structs: Vec<MyStruct> = serde_json::from_str(json).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(structs[0].field, true);
|
||||||
|
assert_eq!(structs[1].field, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dont_deserialize_invalid_number() {
|
||||||
|
let invalids = [
|
||||||
|
r#"{"field":2}"#,
|
||||||
|
r#"{"field":3}"#,
|
||||||
|
r#"{"field":4}"#,
|
||||||
|
r#"{"field":-1}"#,
|
||||||
|
];
|
||||||
|
|
||||||
|
for case in invalids {
|
||||||
|
assert!(serde_json::from_str::<MyStruct>(case).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dont_deserialize_strings() {
|
||||||
|
let invalids = [
|
||||||
|
r#"{"field":"1"}"#,
|
||||||
|
r#"{"field":"0"}"#,
|
||||||
|
r#"{"field":"true"}"#,
|
||||||
|
r#"{"field":"false"}"#,
|
||||||
|
];
|
||||||
|
|
||||||
|
for case in invalids {
|
||||||
|
assert!(serde_json::from_str::<MyStruct>(case).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn round_trip() {
|
||||||
|
let structs = vec![
|
||||||
|
MyStruct {
|
||||||
|
field: XsdBoolean(false),
|
||||||
|
},
|
||||||
|
MyStruct {
|
||||||
|
field: XsdBoolean(true),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let string = serde_json::to_string(&structs).unwrap();
|
||||||
|
let new_structs: Vec<MyStruct> = serde_json::from_str(&string).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(structs, new_structs);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue