From af3facfbf0c50f29b16c143b6f9eff3b38433275 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 30 Dec 2022 10:41:37 +0100 Subject: [PATCH] Add mastodon_async_entities This patch move the entities module to a helper-crate. With this, we give the user the opportunity to use only the entities types in their codebase, if need be. One scenario where this is required came up in https://github.com/dscottboggs/mastodon-async/issues/38 TL;DR is: A user needed to be able to pass types like `Status` from a backend part of an application to a frontend which was compiled to WASM. Because mastodon_async depends on tokio, which does not compile to WASM (at least not with the features required by mastodon_async). One option would have been to provide types in the application code which can be constructed from mastodon_asyncs entity types. This would lead to _a lot_ of code duplication (over several projects still,... but that's rather undesireable anyways). The solution mastodon_async offers with this patch is a helper-crate which only contains the entity types: mastodon_async_entities. mastodon_async publicly exports the whole mastodon_async_entities crate, so users do not have to depend on the latter directly. In addition to the `entities` module from mastodon_async, also the `Visibility` type had to be moved. `mastodon_async_entities` also got an own `Error` type, which `mastodon_async::Error` can of course wrap. Signed-off-by: Matthias Beyer Suggested-by: D. Scott Boggs --- Cargo.toml | 12 ++++ entities/Cargo.toml | 13 ++++ {src/entities => entities/src}/account.rs | 27 ++++--- {src/entities => entities/src}/attachment.rs | 0 {src/entities => entities/src}/card.rs | 0 {src/entities => entities/src}/context.rs | 0 entities/src/error.rs | 6 ++ {src/entities => entities/src}/event.rs | 2 +- {src/entities => entities/src}/filter.rs | 0 {src/entities => entities/src}/instance.rs | 0 entities/src/lib.rs | 66 +++++++++++++++++ {src/entities => entities/src}/list.rs | 0 {src/entities => entities/src}/mention.rs | 0 .../entities => entities/src}/notification.rs | 0 {src/entities => entities/src}/push.rs | 70 +++++++++---------- .../entities => entities/src}/relationship.rs | 0 {src/entities => entities/src}/report.rs | 0 .../src}/search_result.rs | 0 {src/entities => entities/src}/status.rs | 2 +- entities/src/visibility.rs | 38 ++++++++++ src/entities/mod.rs | 60 +--------------- src/errors.rs | 3 + src/lib.rs | 5 +- src/requests/update_credentials.rs | 12 ++-- src/status_builder.rs | 44 ++---------- 25 files changed, 202 insertions(+), 158 deletions(-) create mode 100644 entities/Cargo.toml rename {src/entities => entities/src}/account.rs (86%) rename {src/entities => entities/src}/attachment.rs (100%) rename {src/entities => entities/src}/card.rs (100%) rename {src/entities => entities/src}/context.rs (100%) create mode 100644 entities/src/error.rs rename {src/entities => entities/src}/event.rs (83%) rename {src/entities => entities/src}/filter.rs (100%) rename {src/entities => entities/src}/instance.rs (100%) create mode 100644 entities/src/lib.rs rename {src/entities => entities/src}/list.rs (100%) rename {src/entities => entities/src}/mention.rs (100%) rename {src/entities => entities/src}/notification.rs (100%) rename {src/entities => entities/src}/push.rs (66%) rename {src/entities => entities/src}/relationship.rs (100%) rename {src/entities => entities/src}/report.rs (100%) rename {src/entities => entities/src}/search_result.rs (100%) rename {src/entities => entities/src}/status.rs (98%) create mode 100644 entities/src/visibility.rs diff --git a/Cargo.toml b/Cargo.toml index dd6923a..107aec6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,11 @@ +[workspace] +resolver = "2" + +members = [ + ".", + "entities", +] + [package] name = "mastodon-async" version = "1.0.3" @@ -13,6 +21,10 @@ repository = "https://github.com/dscottboggs/mastodon-async.git" [package.metadata.docs.rs] features = ["all"] +[dependencies.mastodon-async-entities] +path = "./entities" +version = "1.0.3" + [dependencies] futures = "0.3.25" doc-comment = "0.3" diff --git a/entities/Cargo.toml b/entities/Cargo.toml new file mode 100644 index 0000000..15ff891 --- /dev/null +++ b/entities/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "mastodon-async-entities" +version = "1.0.3" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +futures = "0.3.25" +log = { version = "0.4", features = ["kv_unstable", "serde", "std", "kv_unstable_serde", "kv_unstable_std"] } +serde = { version = "1", features = ["derive"] } +thiserror = "1" +time = { version = "0.3", features = ["parsing", "serde", "formatting"] } diff --git a/src/entities/account.rs b/entities/src/account.rs similarity index 86% rename from src/entities/account.rs rename to entities/src/account.rs index 3a82f17..2afd9b3 100644 --- a/src/entities/account.rs +++ b/entities/src/account.rs @@ -1,6 +1,5 @@ //! A module containing everything relating to a account returned from the api. -use crate::status_builder; use serde::{ de::{self, Deserializer, Unexpected}, Deserialize, Serialize, @@ -65,7 +64,7 @@ pub struct MetadataField { } impl MetadataField { - pub(crate) fn new(name: &str, value: &str) -> MetadataField { + pub fn new(name: &str, value: &str) -> MetadataField { MetadataField { name: name.into(), value: value.into(), @@ -76,7 +75,7 @@ impl MetadataField { /// An extra object given from `verify_credentials` giving defaults about a user #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub struct Source { - privacy: Option, + privacy: Option, #[serde(deserialize_with = "string_or_bool")] sensitive: bool, note: Option, @@ -109,33 +108,33 @@ fn string_or_bool<'de, D: Deserializer<'de>>(val: D) -> ::std::result::Result, + pub privacy: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) sensitive: Option, + pub sensitive: Option, } #[derive(Debug, Default, Serialize, PartialEq, Eq)] -pub(crate) struct Credentials { +pub struct Credentials { #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) display_name: Option, + pub display_name: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) note: Option, + pub note: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) avatar: Option, + pub avatar: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) header: Option, + pub header: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) source: Option, + pub source: Option, #[serde(serialize_with = "fields_attributes_ser::ser")] - pub(crate) fields_attributes: Vec, + pub fields_attributes: Vec, } mod fields_attributes_ser { use super::*; use serde::ser::{SerializeMap, Serializer}; - pub(crate) fn ser(attrs: &Vec, serializer: S) -> Result + pub fn ser(attrs: &Vec, serializer: S) -> Result where S: Serializer, { diff --git a/src/entities/attachment.rs b/entities/src/attachment.rs similarity index 100% rename from src/entities/attachment.rs rename to entities/src/attachment.rs diff --git a/src/entities/card.rs b/entities/src/card.rs similarity index 100% rename from src/entities/card.rs rename to entities/src/card.rs diff --git a/src/entities/context.rs b/entities/src/context.rs similarity index 100% rename from src/entities/context.rs rename to entities/src/context.rs diff --git a/entities/src/error.rs b/entities/src/error.rs new file mode 100644 index 0000000..d4e52ce --- /dev/null +++ b/entities/src/error.rs @@ -0,0 +1,6 @@ +/// Error type +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("unrecognized visibility '{invalid}'")] + VisibilityParsingError { invalid: String }, +} diff --git a/src/entities/event.rs b/entities/src/event.rs similarity index 83% rename from src/entities/event.rs rename to entities/src/event.rs index 3dca536..007aedd 100644 --- a/src/entities/event.rs +++ b/entities/src/event.rs @@ -1,4 +1,4 @@ -use crate::entities::{notification::Notification, status::Status}; +use crate::{notification::Notification, status::Status}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/src/entities/filter.rs b/entities/src/filter.rs similarity index 100% rename from src/entities/filter.rs rename to entities/src/filter.rs diff --git a/src/entities/instance.rs b/entities/src/instance.rs similarity index 100% rename from src/entities/instance.rs rename to entities/src/instance.rs diff --git a/entities/src/lib.rs b/entities/src/lib.rs new file mode 100644 index 0000000..6a58e8c --- /dev/null +++ b/entities/src/lib.rs @@ -0,0 +1,66 @@ +use serde::Deserialize; +use serde::Serialize; + +/// Error types for this crate +pub mod error; + +/// Data structures for ser/de of account-related resources +pub mod account; +/// Data structures for ser/de of attachment-related resources +pub mod attachment; +/// Data structures for ser/de of card-related resources +pub mod card; +/// Data structures for ser/de of contetx-related resources +pub mod context; +/// Data structures for ser/de of streaming events +pub mod event; +/// Data structures for ser/de of filter-related resources +pub mod filter; +/// Data structures for ser/de of instance-related resources +pub mod instance; +/// Data structures for ser/de of list-related resources +pub mod list; +/// Data structures for ser/de of mention-related resources +pub mod mention; +/// Data structures for ser/de of notification-related resources +pub mod notification; +/// Data structures for ser/de of push-subscription-related resources +pub mod push; +/// Data structures for ser/de of relationship-related resources +pub mod relationship; +/// Data structures for ser/de of report-related resources +pub mod report; +/// Data structures for ser/de of search-related resources +pub mod search_result; +/// Data structures for ser/de of status-related resources +pub mod status; +/// Data structure for ser/de visibility +pub mod visibility; + +/// An empty JSON object. +#[derive(Deserialize, Serialize, Debug, Copy, Clone, PartialEq, Eq)] +pub struct Empty {} + +/// The purpose of this module is to alleviate imports of many common +/// structs by adding a glob import to the top of mastodon heavy +/// modules: +pub mod prelude { + pub use super::{ + account::{Account, Source}, + attachment::{Attachment, MediaType}, + card::Card, + context::Context, + event::Event, + filter::{Filter, FilterContext}, + instance::*, + list::List, + mention::Mention, + notification::Notification, + push::Subscription, + relationship::Relationship, + report::Report, + search_result::SearchResult, + status::{Application, Emoji, Status}, + Empty, + }; +} diff --git a/src/entities/list.rs b/entities/src/list.rs similarity index 100% rename from src/entities/list.rs rename to entities/src/list.rs diff --git a/src/entities/mention.rs b/entities/src/mention.rs similarity index 100% rename from src/entities/mention.rs rename to entities/src/mention.rs diff --git a/src/entities/notification.rs b/entities/src/notification.rs similarity index 100% rename from src/entities/notification.rs rename to entities/src/notification.rs diff --git a/src/entities/push.rs b/entities/src/push.rs similarity index 66% rename from src/entities/push.rs rename to entities/src/push.rs index 09d392c..c86f899 100644 --- a/src/entities/push.rs +++ b/entities/src/push.rs @@ -26,48 +26,48 @@ pub struct Subscription { pub alerts: Option, } -pub(crate) mod add_subscription { - use serde::Serialize; - - use super::Alerts; - - #[derive(Debug, Clone, PartialEq, Serialize, Default)] - pub(crate) struct Form { - pub(crate) subscription: Subscription, - pub(crate) data: Option, - } - - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] - pub(crate) struct Subscription { - pub(crate) endpoint: String, - pub(crate) keys: Keys, - } - - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] - pub(crate) struct Keys { - pub(crate) p256dh: String, - pub(crate) auth: String, - } - - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] - pub(crate) struct Data { - pub(crate) alerts: Option, - } -} - -pub(crate) mod update_data { +pub mod add_subscription { use serde::Serialize; use super::Alerts; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] - pub(crate) struct Data { - pub(crate) alerts: Option, + pub struct Form { + pub subscription: Subscription, + pub data: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] - pub(crate) struct Form { - pub(crate) id: String, - pub(crate) data: Data, + pub struct Subscription { + pub endpoint: String, + pub keys: Keys, + } + + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] + pub struct Keys { + pub p256dh: String, + pub auth: String, + } + + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] + pub struct Data { + pub alerts: Option, + } +} + +pub mod update_data { + use serde::Serialize; + + use super::Alerts; + + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] + pub struct Data { + pub alerts: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)] + pub struct Form { + pub id: String, + pub data: Data, } } diff --git a/src/entities/relationship.rs b/entities/src/relationship.rs similarity index 100% rename from src/entities/relationship.rs rename to entities/src/relationship.rs diff --git a/src/entities/report.rs b/entities/src/report.rs similarity index 100% rename from src/entities/report.rs rename to entities/src/report.rs diff --git a/src/entities/search_result.rs b/entities/src/search_result.rs similarity index 100% rename from src/entities/search_result.rs rename to entities/src/search_result.rs diff --git a/src/entities/status.rs b/entities/src/status.rs similarity index 98% rename from src/entities/status.rs rename to entities/src/status.rs index 89414cd..eddda74 100644 --- a/src/entities/status.rs +++ b/entities/src/status.rs @@ -1,7 +1,7 @@ //! Module containing all info relating to a status. use super::prelude::*; -use crate::{entities::card::Card, status_builder::Visibility}; +use crate::{card::Card, visibility::Visibility}; use serde::{Deserialize, Serialize}; use time::{serde::iso8601, OffsetDateTime}; diff --git a/entities/src/visibility.rs b/entities/src/visibility.rs new file mode 100644 index 0000000..590c550 --- /dev/null +++ b/entities/src/visibility.rs @@ -0,0 +1,38 @@ +use serde::Deserialize; +use serde::Serialize; + +/// The visibility of a status. +#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum Visibility { + /// A Direct message to a user + Direct, + /// Only available to followers + Private, + /// Not shown in public timelines + Unlisted, + /// Posted to public timelines + Public, +} + +impl Default for Visibility { + fn default() -> Self { + Visibility::Public + } +} + +impl std::str::FromStr for Visibility { + type Err = crate::error::Error; + + fn from_str(s: &str) -> Result { + match s.to_ascii_lowercase().as_str() { + "direct" => Ok(Visibility::Direct), + "private" => Ok(Visibility::Private), + "unlisted" => Ok(Visibility::Unlisted), + "public" => Ok(Visibility::Public), + invalid => Err(crate::error::Error::VisibilityParsingError { + invalid: invalid.to_string(), + }), + } + } +} diff --git a/src/entities/mod.rs b/src/entities/mod.rs index 37ff8b3..d565d20 100644 --- a/src/entities/mod.rs +++ b/src/entities/mod.rs @@ -1,61 +1,3 @@ -use serde::Deserialize; - -/// Data structures for ser/de of account-related resources -pub mod account; -/// Data structures for ser/de of attachment-related resources -pub mod attachment; -/// Data structures for ser/de of card-related resources -pub mod card; -/// Data structures for ser/de of contetx-related resources -pub mod context; -/// Data structures for ser/de of streaming events -pub mod event; -/// Data structures for ser/de of filter-related resources -pub mod filter; -/// Data structures for ser/de of instance-related resources -pub mod instance; pub(crate) mod itemsiter; -/// Data structures for ser/de of list-related resources -pub mod list; -/// Data structures for ser/de of mention-related resources -pub mod mention; -/// Data structures for ser/de of notification-related resources -pub mod notification; -/// Data structures for ser/de of push-subscription-related resources -pub mod push; -/// Data structures for ser/de of relationship-related resources -pub mod relationship; -/// Data structures for ser/de of report-related resources -pub mod report; -/// Data structures for ser/de of search-related resources -pub mod search_result; -/// Data structures for ser/de of status-related resources -pub mod status; -/// An empty JSON object. -#[derive(Deserialize, Serialize, Debug, Copy, Clone, PartialEq, Eq)] -pub struct Empty {} - -/// The purpose of this module is to alleviate imports of many common -/// structs by adding a glob import to the top of mastodon heavy -/// modules: -pub mod prelude { - pub use super::{ - account::{Account, Source}, - attachment::{Attachment, MediaType}, - card::Card, - context::Context, - event::Event, - filter::{Filter, FilterContext}, - instance::*, - list::List, - mention::Mention, - notification::Notification, - push::Subscription, - relationship::Relationship, - report::Report, - search_result::SearchResult, - status::{Application, Emoji, Status}, - Empty, - }; -} +pub use mastodon_async_entities::*; diff --git a/src/errors.rs b/src/errors.rs index d018b34..1459d71 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -99,6 +99,9 @@ pub enum Error { /// larger than the system's usize allows. #[error("integer didn't fit in the target size")] IntConversion(#[from] TryFromIntError), + /// Error from mastodon-async-entities + #[error(transparent)] + Entities(#[from] mastodon_async_entities::error::Error), /// Other errors #[error("other error: {0:?}")] Other(String), diff --git a/src/lib.rs b/src/lib.rs index 42ac7c0..0c9c6e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,11 +92,12 @@ pub use errors::{ApiError, Error, Result}; pub use isolang::Language; pub use mastodon::{Mastodon, MastodonUnauthenticated}; // pub use mastodon_client::{MastodonClient, MastodonUnauthenticated}; +pub use mastodon_async_entities::visibility::Visibility; pub use registration::Registration; pub use requests::{ AddFilterRequest, AddPushRequest, StatusesRequest, UpdateCredsRequest, UpdatePushRequest, }; -pub use status_builder::{NewStatus, StatusBuilder, Visibility}; +pub use status_builder::{NewStatus, StatusBuilder}; /// Registering your App pub mod apps; @@ -126,7 +127,6 @@ mod macros; pub mod prelude { pub use crate::{ scopes::Scopes, - status_builder::Visibility, Data, Mastodon, // MastodonClient, @@ -134,6 +134,7 @@ pub mod prelude { Registration, StatusBuilder, StatusesRequest, + Visibility, }; } /// The mastodon client diff --git a/src/requests/update_credentials.rs b/src/requests/update_credentials.rs index c185a26..d24a75a 100644 --- a/src/requests/update_credentials.rs +++ b/src/requests/update_credentials.rs @@ -6,15 +6,15 @@ use std::{ use crate::{ entities::account::{Credentials, MetadataField, UpdateSource}, errors::Result, - status_builder, }; +use mastodon_async_entities::visibility::Visibility; /// Builder to pass to the Mastodon::update_credentials method /// /// // Example /// /// ```no_run -/// use mastodon_async::{prelude::*, status_builder::Visibility, UpdateCredsRequest}; +/// use mastodon_async::{prelude::*, entities::visibility::Visibility, UpdateCredsRequest}; /// /// let data = Data::default(); /// let client = Mastodon::from(data); @@ -35,7 +35,7 @@ pub struct UpdateCredsRequest { field_attributes: Vec, // UpdateSource fields - privacy: Option, + privacy: Option, sensitive: Option, } @@ -126,13 +126,13 @@ impl UpdateCredsRequest { /// // Example /// /// ``` - /// use mastodon_async::{status_builder::Visibility, UpdateCredsRequest}; + /// use mastodon_async::{entities::visibility::Visibility, UpdateCredsRequest}; /// /// let mut builder = UpdateCredsRequest::new(); /// /// builder.privacy(Visibility::Public); /// ``` - pub fn privacy(&mut self, privacy: status_builder::Visibility) -> &mut Self { + pub fn privacy(&mut self, privacy: Visibility) -> &mut Self { self.privacy = Some(privacy); self } @@ -188,7 +188,7 @@ impl UpdateCredsRequest { mod tests { use super::*; use crate::entities::account::{Credentials, MetadataField, UpdateSource}; - use status_builder::Visibility; + use mastodon_async_entities::visibility::Visibility; #[test] fn test_update_creds_request_new() { diff --git a/src/status_builder.rs b/src/status_builder.rs index bdd8caa..c8d43b4 100644 --- a/src/status_builder.rs +++ b/src/status_builder.rs @@ -1,9 +1,7 @@ -use std::str::FromStr; - use isolang::Language; -use serde::{Deserialize, Serialize}; +use serde::Serialize; -use crate::format_err; +use mastodon_async_entities::visibility::Visibility; /// A builder pattern struct for constructing a status. /// @@ -37,7 +35,7 @@ impl StatusBuilder { /// // Example /// /// ```rust,no_run - /// use mastodon_async::{status_builder::Visibility, prelude::*}; + /// use mastodon_async::{entities::visibility::Visibility, prelude::*}; /// /// let data = Data::default(); /// let client = Mastodon::from(data); @@ -150,7 +148,7 @@ impl StatusBuilder { /// // Example /// /// ```rust - /// use mastodon_async::{prelude::*, status_builder::Visibility}; + /// use mastodon_async::{prelude::*, entities::visibility::Visibility}; /// let status = StatusBuilder::new() /// .status("awooooooo") /// .visibility(Visibility::Public) @@ -242,40 +240,6 @@ pub struct NewStatus { content_type: Option, } -/// The visibility of a status. -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "lowercase")] -pub enum Visibility { - /// A Direct message to a user - Direct, - /// Only available to followers - Private, - /// Not shown in public timelines - Unlisted, - /// Posted to public timelines - Public, -} - -impl Default for Visibility { - fn default() -> Self { - Visibility::Public - } -} - -impl FromStr for Visibility { - type Err = crate::Error; - - fn from_str(s: &str) -> Result { - match s.to_ascii_lowercase().as_str() { - "direct" => Ok(Visibility::Direct), - "private" => Ok(Visibility::Private), - "unlisted" => Ok(Visibility::Unlisted), - "public" => Ok(Visibility::Public), - invalid => Err(format_err!("unrecognized visibility '{invalid}'")), - } - } -} - #[cfg(test)] mod tests { use super::*;