diff --git a/activitystreams-derive/src/lib.rs b/activitystreams-derive/src/lib.rs index d60f5b9..7ecf797 100644 --- a/activitystreams-derive/src/lib.rs +++ b/activitystreams-derive/src/lib.rs @@ -52,7 +52,7 @@ pub fn unit_string(input: TokenStream) -> TokenStream { .unwrap() .clone(); - let value = get_value(attr); + let value = from_value(attr); let visitor_name = Ident::from(format!("{}Visitor", value)); @@ -118,7 +118,7 @@ pub fn unit_string(input: TokenStream) -> TokenStream { c.into() } -fn get_value(attr: Attribute) -> String { +fn from_value(attr: Attribute) -> String { let group = attr.tts .clone() .into_iter() @@ -218,12 +218,19 @@ pub fn properties_derive(input: TokenStream) -> TokenStream { let lower_variant = variant.to_lowercase(); let fn_name = Ident::from(format!("{}_{}", ident, lower_variant)); let fn_plural = Ident::from(format!("{}_{}_vec", ident, lower_variant)); + let set_fn_name = Ident::from(format!("set_{}_{}", ident, lower_variant)); + let set_fn_plural = Ident::from(format!("set_{}_{}_vec", ident, lower_variant)); let variant = Ident::from(variant); if is_concrete && is_option { let single = quote! { pub fn #fn_name(&self) -> ::error::Result<#variant> { - ::properties::get_item(&self.#ident) + ::properties::from_item(&self.#ident) + } + + pub fn #set_fn_name(&mut self, item: #variant) -> ::error::Result<()> { + self.#ident = ::properties::to_item(item)?; + Ok(()) } }; @@ -234,20 +241,35 @@ pub fn properties_derive(input: TokenStream) -> TokenStream { #single pub fn #fn_plural(&self) -> ::error::Result> { - ::properties::get_item(&self.#ident) + ::properties::from_item(&self.#ident) + } + + pub fn #set_fn_plural(&mut self, item: Vec<#variant>) -> ::error::Result<()> { + self.#ident = ::properties::to_item(item)?; + Ok(()) } } } } else if is_concrete && is_vec { quote! { pub fn #fn_name(&self) -> ::error::Result> { - ::properties::get_vec(&self.#ident) + ::properties::from_vec(&self.#ident) + } + + pub fn #set_fn_name(&mut self, item: Vec<#variant>>) -> ::error::Result<()> { + self.#ident = ::properties::to_vec(item)?; + Ok(()) } } } else if is_concrete { let single = quote! { pub fn #fn_name(&self) -> ::error::Result<#variant> { - ::properties::get_value(&self.#ident) + ::properties::from_value(&self.#ident) + } + + pub fn #set_fn_name(&mut self, item: #variant) -> ::error::Result<()> { + self.#ident = ::properties::to_value(item)?; + Ok(()) } }; @@ -258,14 +280,24 @@ pub fn properties_derive(input: TokenStream) -> TokenStream { #single pub fn #fn_plural(&self) -> ::error::Result> { - ::properties::get_value(&self.#ident) + ::properties::from_value(&self.#ident) + } + + pub #set_fn_plural(&mut self, item: Vec<#variant>) -> ::error::Result<()> { + self.#ident = ::properties::to_value(item)?; + Ok(()) } } } } else if is_option { let single = quote! { pub fn #fn_name(&self) -> ::error::Result { - ::properties::get_item(&self.#ident) + ::properties::from_item(&self.#ident) + } + + pub fn #set_fn_name(&mut self, item: T) -> ::error::Result<()> { + self.#ident = ::properties::to_item(item)?; + Ok(()) } }; @@ -276,20 +308,35 @@ pub fn properties_derive(input: TokenStream) -> TokenStream { #single pub fn #fn_plural(&self) -> ::error::Result> { - ::properties::get_item(&self.#ident) + ::properties::from_item(&self.#ident) + } + + pub fn #set_fn_plural(&mut self, item: Vec) -> ::error::Result<()> { + self.#ident = ::properties::to_item(item)?; + Ok(()) } } } } else if is_vec { quote! { pub fn #fn_name(&self) -> ::error::Result> { - ::properties::get_vec(&self.#ident) + ::properties::from_vec(&self.#ident) + } + + pub fn #set_fn_name(&mut self, item: Vec) -> ::error::Result<()> { + self.#ident = ::properties::to_vec(item)?; + Ok(()) } } } else { let single = quote! { pub fn #fn_name(&self) -> ::error::Result { - ::properties::get_value(&self.#ident) + ::properties::from_value(&self.#ident) + } + + pub fn #set_fn_name(&mut self, item: T) -> ::error::Result<()> { + self.#ident = ::properties::to_value(item)?; + Ok(()) } }; @@ -300,7 +347,12 @@ pub fn properties_derive(input: TokenStream) -> TokenStream { #single pub fn #fn_plural(&self) -> ::error::Result> { - ::properties::get_value(&self.#ident) + ::properties::from_value(&self.#ident) + } + + pub fn #set_fn_plural(&mut self, item: Vec) -> ::error::Result<()> { + self.#ident = ::properties::to_value(item)?; + Ok(()) } } } diff --git a/src/custom_props.rs b/src/custom_props.rs new file mode 100644 index 0000000..752ccc1 --- /dev/null +++ b/src/custom_props.rs @@ -0,0 +1,56 @@ +/* + * This file is part of ActivityStreams. + * + * Copyright © 2018 Riley Trautman + * + * ActivityStreams is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityStreams is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityStreams. If not, see . + */ + +use link::Link; +use object::Object; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CustomLink { + #[serde(flatten)] + link: L, + + #[serde(flatten)] + pub custom_props: C, +} + +impl CustomLink { + pub fn new(link: L, custom_props: C) -> Self { + CustomLink { link, custom_props } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CustomObject { + #[serde(flatten)] + object: O, + + #[serde(flatten)] + pub custom_props: C, +} + +impl CustomObject { + pub fn new(object: O, custom_props: C) -> Self { + CustomObject { + object, + custom_props, + } + } +} diff --git a/src/error.rs b/src/error.rs index fb022b3..81998ed 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,8 +23,12 @@ use std::result; pub enum Error { #[fail(display = "Key not present")] NotFound, + #[fail(display = "Failed to deserialize data as requested type")] Deserialize, + + #[fail(display = "Failed to serialize data")] + Serialize, } pub type Result = result::Result; diff --git a/src/lib.rs b/src/lib.rs index 6bb3f75..f039f87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,7 @@ pub fn context() -> serde_json::Value { pub mod activity; pub mod actor; pub mod collection; +pub mod custom_props; pub mod error; pub mod link; pub mod object; diff --git a/src/properties.rs b/src/properties.rs index 3fabbb9..f7e6344 100644 --- a/src/properties.rs +++ b/src/properties.rs @@ -1,38 +1,81 @@ -use serde::de::DeserializeOwned; +/* + * This file is part of ActivityStreams. + * + * Copyright © 2018 Riley Trautman + * + * ActivityStreams is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityStreams is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityStreams. If not, see . + */ + +use serde::{de::DeserializeOwned, ser::Serialize}; use serde_json; use error::{Error, Result}; -pub fn get_value(item: &serde_json::Value) -> Result +pub fn from_value(item: &serde_json::Value) -> Result where I: DeserializeOwned, { serde_json::from_value(item.clone()).map_err(|_| Error::Deserialize) } -pub fn get_item(item: &Option) -> Result +pub fn to_value(item: I) -> Result +where + I: Serialize, +{ + serde_json::to_value(item).map_err(|_| Error::Serialize) +} + +pub fn from_item(item: &Option) -> Result where I: DeserializeOwned, { if let &Some(ref item) = item { - serde_json::from_value(item.clone()).map_err(|_| Error::Deserialize) + from_value(item) } else { Err(Error::NotFound) } } -pub fn get_vec(v: &Vec) -> Result> +pub fn to_item(item: I) -> Result> +where + I: Serialize, +{ + to_value(item).map(Some) +} + +pub fn from_vec(v: &Vec) -> Result> where I: DeserializeOwned, { v.iter().fold(Ok(Vec::new()), |acc, item| match acc { - Ok(mut acc) => match serde_json::from_value(item.clone()) { - Ok(item) => { - acc.push(item); - Ok(acc) - } - Err(_) => Err(Error::Deserialize), - }, - Err(e) => Err(e), + Ok(mut acc) => from_value(item).map(|item| { + acc.push(item); + acc + }), + e => e, + }) +} + +pub fn to_vec(v: Vec) -> Result> +where + I: Serialize, +{ + v.into_iter().fold(Ok(Vec::new()), |acc, item| match acc { + Ok(mut acc) => to_value(item).map(|item| { + acc.push(item); + acc + }), + e => e, }) }