diff options
author | Paul Woolcock <paul@woolcock.us> | 2020-06-09 09:11:18 -0400 |
---|---|---|
committer | Paul Woolcock <paul@woolcock.us> | 2020-06-11 12:09:52 -0400 |
commit | 16bc060407fc23660994bf3f4894cfecf2a46148 (patch) | |
tree | 2551738ee5e24747070c7b7fdd752b7762da9dc6 | |
parent | 17c727f5c615eed921d0095d1b6f49e44024025d (diff) |
Update to the 2018 edition
Only 2 years later :eyeroll:
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | examples/follow_profile.rs | 4 | ||||
-rw-r--r-- | examples/follows_me.rs | 4 | ||||
-rw-r--r-- | examples/home_timeline.rs | 4 | ||||
-rw-r--r-- | examples/print_your_profile.rs | 4 | ||||
-rw-r--r-- | examples/register/mod.rs | 8 | ||||
-rw-r--r-- | examples/search.rs | 4 | ||||
-rw-r--r-- | examples/upload_photo.rs | 4 | ||||
-rw-r--r-- | macro-dbg | 30158 | ||||
-rw-r--r-- | src/apps.rs | 4 | ||||
-rw-r--r-- | src/entities/account.rs | 2 | ||||
-rw-r--r-- | src/entities/event.rs | 2 | ||||
-rw-r--r-- | src/entities/itemsiter.rs | 4 | ||||
-rw-r--r-- | src/entities/status.rs | 4 | ||||
-rw-r--r-- | src/errors.rs | 8 | ||||
-rw-r--r-- | src/helpers/cli.rs | 8 | ||||
-rw-r--r-- | src/helpers/env.rs | 4 | ||||
-rw-r--r-- | src/helpers/json.rs | 4 | ||||
-rw-r--r-- | src/helpers/toml.rs | 6 | ||||
-rw-r--r-- | src/http_send.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 38 | ||||
-rw-r--r-- | src/mastodon_client.rs | 12 | ||||
-rw-r--r-- | src/page.rs | 4 | ||||
-rw-r--r-- | src/registration.rs | 16 | ||||
-rw-r--r-- | src/requests/filter.rs | 2 | ||||
-rw-r--r-- | src/requests/push.rs | 10 | ||||
-rw-r--r-- | src/requests/statuses.rs | 2 | ||||
-rw-r--r-- | src/requests/update_credentials.rs | 10 | ||||
-rw-r--r-- | src/scopes.rs | 2 |
29 files changed, 30247 insertions, 88 deletions
@@ -8,6 +8,7 @@ readme = "README.md" repository = "https://github.com/pwoolcoc/elefren.git" keywords = ["api", "web", "social", "mastodon", "wrapper"] categories = ["web-programming", "web-programming::http-client", "api-bindings"] +edition = "2018" [dependencies] doc-comment = "0.3" diff --git a/examples/follow_profile.rs b/examples/follow_profile.rs index 84b2998..2d97380 100644 --- a/examples/follow_profile.rs +++ b/examples/follow_profile.rs @@ -5,11 +5,11 @@ extern crate pretty_env_logger; extern crate elefren; mod register; -use register::MastodonClient; +use crate::register::MastodonClient; use std::error; #[cfg(feature = "toml")] -fn main() -> Result<(), Box<error::Error>> { +fn main() -> Result<(), Box<dyn error::Error>> { let mastodon = register::get_mastodon_data()?; let input = register::read_line("Enter the account id you'd like to follow: ")?; let new_follow = mastodon.follow(input.trim())?; diff --git a/examples/follows_me.rs b/examples/follows_me.rs index 0df4414..2008fb5 100644 --- a/examples/follows_me.rs +++ b/examples/follows_me.rs @@ -5,11 +5,11 @@ extern crate pretty_env_logger; extern crate elefren; mod register; -use register::MastodonClient; +use crate::register::MastodonClient; use std::error; #[cfg(feature = "toml")] -fn main() -> Result<(), Box<error::Error>> { +fn main() -> Result<(), Box<dyn error::Error>> { let mastodon = register::get_mastodon_data()?; for account in mastodon.follows_me()?.items_iter() { println!("{}", account.acct); diff --git a/examples/home_timeline.rs b/examples/home_timeline.rs index 46519e3..0f3c920 100644 --- a/examples/home_timeline.rs +++ b/examples/home_timeline.rs @@ -5,11 +5,11 @@ extern crate pretty_env_logger; extern crate elefren; mod register; -use register::MastodonClient; +use crate::register::MastodonClient; use std::error; #[cfg(feature = "toml")] -fn main() -> Result<(), Box<error::Error>> { +fn main() -> Result<(), Box<dyn error::Error>> { let mastodon = register::get_mastodon_data()?; let tl = mastodon.get_home_timeline()?; diff --git a/examples/print_your_profile.rs b/examples/print_your_profile.rs index cbcd372..126110a 100644 --- a/examples/print_your_profile.rs +++ b/examples/print_your_profile.rs @@ -5,11 +5,11 @@ extern crate pretty_env_logger; extern crate elefren; mod register; -use register::MastodonClient; +use crate::register::MastodonClient; use std::error; #[cfg(feature = "toml")] -fn main() -> Result<(), Box<error::Error>> { +fn main() -> Result<(), Box<dyn error::Error>> { let mastodon = register::get_mastodon_data()?; let you = mastodon.verify_credentials()?; diff --git a/examples/register/mod.rs b/examples/register/mod.rs index d8dbaff..1c429b5 100644 --- a/examples/register/mod.rs +++ b/examples/register/mod.rs @@ -11,14 +11,14 @@ use elefren::helpers::toml; #[allow(dead_code)] #[cfg(feature = "toml")] -fn main() -> Result<(), Box<Error>> { +fn main() -> Result<(), Box<dyn Error>> { register()?; Ok(()) } #[allow(dead_code)] #[cfg(feature = "toml")] -pub fn get_mastodon_data() -> Result<Mastodon, Box<Error>> { +pub fn get_mastodon_data() -> Result<Mastodon, Box<dyn Error>> { if let Ok(data) = toml::from_file("mastodon-data.toml") { Ok(Mastodon::from(data)) } else { @@ -27,7 +27,7 @@ pub fn get_mastodon_data() -> Result<Mastodon, Box<Error>> { } #[cfg(feature = "toml")] -pub fn register() -> Result<Mastodon, Box<Error>> { +pub fn register() -> Result<Mastodon, Box<dyn Error>> { let website = read_line("Please enter your mastodon instance url:")?; let registration = Registration::new(website.trim()) .client_name("elefren-examples") @@ -43,7 +43,7 @@ pub fn register() -> Result<Mastodon, Box<Error>> { } #[cfg(feature = "toml")] -pub fn read_line(message: &str) -> Result<String, Box<Error>> { +pub fn read_line(message: &str) -> Result<String, Box<dyn Error>> { println!("{}", message); let mut input = String::new(); diff --git a/examples/search.rs b/examples/search.rs index ec13f6d..c619a74 100644 --- a/examples/search.rs +++ b/examples/search.rs @@ -5,11 +5,11 @@ extern crate pretty_env_logger; extern crate elefren; mod register; -use register::MastodonClient; +use crate::register::MastodonClient; use std::error; #[cfg(feature = "toml")] -fn main() -> Result<(), Box<error::Error>> { +fn main() -> Result<(), Box<dyn error::Error>> { let mastodon = register::get_mastodon_data()?; let input = register::read_line("Enter the term you'd like to search: ")?; let result = mastodon.search(&input, false)?; diff --git a/examples/upload_photo.rs b/examples/upload_photo.rs index a2e6688..fa2dee9 100644 --- a/examples/upload_photo.rs +++ b/examples/upload_photo.rs @@ -5,11 +5,11 @@ extern crate pretty_env_logger; extern crate elefren; mod register; -use register::MastodonClient; +use crate::register::MastodonClient; use std::error; #[cfg(feature = "toml")] -fn main() -> Result<(), Box<error::Error>> { +fn main() -> Result<(), Box<dyn error::Error>> { let mastodon = register::get_mastodon_data()?; let input = register::read_line("Enter the path to the photo you'd like to post: ")?; diff --git a/macro-dbg b/macro-dbg new file mode 100644 index 0000000..27be5c5 --- /dev/null +++ b/macro-dbg @@ -0,0 +1,30158 @@ +#![feature(prelude_import)] +//! # Elefren: API Wrapper around the Mastodon API. +//! +//! Most of the api is documented on [Mastodon's website](https://docs.joinmastodon.org/client/intro/) +//! +//! ```no_run +//! # extern crate elefren; +//! # fn main() { +//! # run().unwrap(); +//! # } +//! # fn run() -> elefren::Result<()> { +//! use elefren::{helpers::cli, prelude::*}; +//! +//! let registration = Registration::new("https://mastodon.social") +//! .client_name("elefren_test") +//! .build()?; +//! let mastodon = cli::authenticate(registration)?; +//! +//! println!( +//! "{:?}", +//! mastodon +//! .get_home_timeline()? +//! .items_iter() +//! .take(100) +//! .collect::<Vec<_>>() +//! ); +//! # Ok(()) +//! # } +//! ``` +//! +//! Elefren also supports Mastodon's Streaming API: +//! +//! # Example +//! +//! ```no_run +//! # extern crate elefren; +//! # use elefren::prelude::*; +//! # use std::error::Error; +//! use elefren::entities::event::Event; +//! # fn main() -> Result<(), Box<Error>> { +//! # let data = Data { +//! # base: "".into(), +//! # client_id: "".into(), +//! # client_secret: "".into(), +//! # redirect: "".into(), +//! # token: "".into(), +//! # }; +//! let client = Mastodon::from(data); +//! for event in client.streaming_user()? { +//! match event { +//! Event::Update(ref status) => { /* .. */ }, +//! Event::Notification(ref notification) => { /* .. */ }, +//! Event::Delete(ref id) => { /* .. */ }, +//! Event::FiltersChanged => { /* .. */ }, +//! } +//! } +//! # Ok(()) +//! # } +//! ``` + +#![deny(missing_docs, warnings, missing_debug_implementations, + missing_copy_implementations, trivial_casts, trivial_numeric_casts, + unsafe_code, unstable_features, unused_import_braces, + unused_qualifications)] +#![allow(intra_doc_link_resolution_failure)] +#[prelude_import] +use std::prelude::v1::*; +#[macro_use] +extern crate std; + +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate doc_comment; +extern crate hyper_old_types; +extern crate isolang; +#[macro_use] +extern crate serde_json; +extern crate chrono; +extern crate reqwest; +extern crate serde; +extern crate serde_qs; +extern crate serde_urlencoded; +extern crate tap_reader; +extern crate try_from; +extern crate url; +extern crate tungstenite; + + + + + +use std::{borrow::Cow, + /* + io::BufRead, + */ + ops}; + +use async_trait::async_trait; +use reqwest::{Client, RequestBuilder, Response}; +use tap_reader::Tap; +/* +use tungstenite::client::AutoStream; +*/ + +use crate::entities::prelude::*; +use crate::page::Page; + +pub use crate::data::Data; +pub use crate::errors::{ApiError, Error, Result}; +pub use isolang::Language; +pub use crate::mastodon_client::{MastodonClient, MastodonUnauthenticated}; +pub use crate::registration::Registration; +pub use crate::requests::{AddFilterRequest, AddPushRequest, StatusesRequest, + UpdateCredsRequest, UpdatePushRequest}; +pub use crate::status_builder::{NewStatus, StatusBuilder}; + +/// Registering your App +pub mod apps { + + + + + + + /* + type Stream = EventReader<WebSocket>; + */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /* + /// returns events that are relevant to the authorized user, i.e. home + /// timeline & notifications + /// + /// # Example + /// + /// ```no_run + /// # extern crate elefren; + /// # use elefren::prelude::*; + /// # use std::error::Error; + /// use elefren::entities::event::Event; + /// # fn main() -> Result<(), Box<Error>> { + /// # let data = Data { + /// # base: "".into(), + /// # client_id: "".into(), + /// # client_secret: "".into(), + /// # redirect: "".into(), + /// # token: "".into(), + /// # }; + /// let client = Mastodon::from(data); + /// for event in client.streaming_user()? { + /// match event { + /// Event::Update(ref status) => { /* .. */ }, + /// Event::Notification(ref notification) => { /* .. */ }, + /// Event::Delete(ref id) => { /* .. */ }, + /// Event::FiltersChanged => { /* .. */ }, + /// } + /// } + /// # Ok(()) + /// # } + /// ``` + fn streaming_user(&self) -> Result<Self::Stream> { + let mut url: url::Url = self.route("/api/v1/streaming").parse()?; + url.query_pairs_mut() + .append_pair("access_token", &self.token) + .append_pair("stream", "user"); + let mut url: url::Url = reqwest::get(url.as_str())?.url().as_str().parse()?; + let new_scheme = match url.scheme() { + "http" => "ws", + "https" => "wss", + x => return Err(Error::Other(format!("Bad URL scheme: {}", x))), + }; + url.set_scheme(new_scheme).map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; + + let client = tungstenite::connect(url.as_str())?.0; + + Ok(EventReader(WebSocket(client))) + } + + /// returns all public statuses + fn streaming_public(&self) -> Result<Self::Stream> { + let mut url: url::Url = self.route("/api/v1/streaming").parse()?; + url.query_pairs_mut() + .append_pair("access_token", &self.token) + .append_pair("stream", "public"); + let mut url: url::Url = reqwest::get(url.as_str())?.url().as_str().parse()?; + let new_scheme = match url.scheme() { + "http" => "ws", + "https" => "wss", + x => return Err(Error::Other(format!("Bad URL scheme: {}", x))), + }; + url.set_scheme(new_scheme).map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; + + let client = tungstenite::connect(url.as_str())?.0; + + Ok(EventReader(WebSocket(client))) + } + + /// Returns all local statuses + fn streaming_local(&self) -> Result<Self::Stream> { + let mut url: url::Url = self.route("/api/v1/streaming").parse()?; + url.query_pairs_mut() + .append_pair("access_token", &self.token) + .append_pair("stream", "public:local"); + let mut url: url::Url = reqwest::get(url.as_str())?.url().as_str().parse()?; + let new_scheme = match url.scheme() { + "http" => "ws", + "https" => "wss", + x => return Err(Error::Other(format!("Bad URL scheme: {}", x))), + }; + url.set_scheme(new_scheme).map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; + + let client = tungstenite::connect(url.as_str())?.0; + + Ok(EventReader(WebSocket(client))) + } + + /// Returns all public statuses for a particular hashtag + fn streaming_public_hashtag(&self, hashtag: &str) -> Result<Self::Stream> { + let mut url: url::Url = self.route("/api/v1/streaming").parse()?; + url.query_pairs_mut() + .append_pair("access_token", &self.token) + .append_pair("stream", "hashtag") + .append_pair("tag", hashtag); + let mut url: url::Url = reqwest::get(url.as_str())?.url().as_str().parse()?; + let new_scheme = match url.scheme() { + "http" => "ws", + "https" => "wss", + x => return Err(Error::Other(format!("Bad URL scheme: {}", x))), + }; + url.set_scheme(new_scheme).map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; + + let client = tungstenite::connect(url.as_str())?.0; + + Ok(EventReader(WebSocket(client))) + } + + /// Returns all local statuses for a particular hashtag + fn streaming_local_hashtag(&self, hashtag: &str) -> Result<Self::Stream> { + let mut url: url::Url = self.route("/api/v1/streaming").parse()?; + url.query_pairs_mut() + .append_pair("access_token", &self.token) + .append_pair("stream", "hashtag:local") + .append_pair("tag", hashtag); + let mut url: url::Url = reqwest::get(url.as_str())?.url().as_str().parse()?; + let new_scheme = match url.scheme() { + "http" => "ws", + "https" => "wss", + x => return Err(Error::Other(format!("Bad URL scheme: {}", x))), + }; + url.set_scheme(new_scheme).map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; + + let client = tungstenite::connect(url.as_str())?.0; + + Ok(EventReader(WebSocket(client))) + } + + /// Returns statuses for a list + fn streaming_list(&self, list_id: &str) -> Result<Self::Stream> { + let mut url: url::Url = self.route("/api/v1/streaming").parse()?; + url.query_pairs_mut() + .append_pair("access_token", &self.token) + .append_pair("stream", "list") + .append_pair("list", list_id); + let mut url: url::Url = reqwest::get(url.as_str())?.url().as_str().parse()?; + let new_scheme = match url.scheme() { + "http" => "ws", + "https" => "wss", + x => return Err(Error::Other(format!("Bad URL scheme: {}", x))), + }; + url.set_scheme(new_scheme).map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; + + let client = tungstenite::connect(url.as_str())?.0; + + Ok(EventReader(WebSocket(client))) + } + + /// Returns all direct messages + fn streaming_direct(&self) -> Result<Self::Stream> { + let mut url: url::Url = self.route("/api/v1/streaming").parse()?; + url.query_pairs_mut() + .append_pair("access_token", &self.token) + .append_pair("stream", "direct"); + let mut url: url::Url = reqwest::get(url.as_str())?.url().as_str().parse()?; + let new_scheme = match url.scheme() { + "http" => "ws", + "https" => "wss", + x => return Err(Error::Other(format!("Bad URL scheme: {}", x))), + }; + url.set_scheme(new_scheme).map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; + + let client = tungstenite::connect(url.as_str())?.0; + + Ok(EventReader(WebSocket(client))) + } + */ + + /* + #[derive(Debug)] + /// WebSocket newtype so that EventStream can be implemented without coherency issues + pub struct WebSocket(tungstenite::protocol::WebSocket<AutoStream>); + + /// A type that streaming events can be read from + pub trait EventStream { + /// Read a message from this stream + fn read_message(&mut self) -> Result<String>; + } + + impl<R: BufRead> EventStream for R { + fn read_message(&mut self) -> Result<String> { + let mut buf = String::new(); + self.read_line(&mut buf)?; + Ok(buf) + } + } + + impl EventStream for WebSocket { + fn read_message(&mut self) -> Result<String> { + Ok(self.0.read_message()?.into_text()?) + } + } + + #[derive(Debug)] + /// Iterator that produces events from a mastodon streaming API event stream + pub struct EventReader<R: EventStream>(R); + impl<R: EventStream> Iterator for EventReader<R> { + type Item = Event; + + fn next(&mut self) -> Option<Self::Item> { + let mut lines = Vec::new(); + loop { + if let Ok(line) = self.0.read_message() { + let line = line.trim().to_string(); + if line.starts_with(":") || line.is_empty() { + continue; + } + lines.push(line); + if let Ok(event) = self.make_event(&lines) { + lines.clear(); + return Some(event); + } else { + continue; + } + } + } + } + } + + impl<R: EventStream> EventReader<R> { + fn make_event(&self, lines: &[String]) -> Result<Event> { + let event; + let data; + if let Some(event_line) = lines + .iter() + .find(|line| line.starts_with("event:")) + { + event = event_line[6..].trim().to_string(); + data = lines.iter().find(|line| line.starts_with("data:")).map(|x| x[5..].trim().to_string()); + } else { + #[derive(Deserialize)] + struct Message { + pub event: String, + pub payload: Option<String>, + } + let message = serde_json::from_str::<Message>(&lines[0])?; + event = message.event; + data = message.payload; + } + let event: &str = &event; + Ok(match event { + "notification" => { + let data = data.ok_or_else(|| { + Error::Other("Missing `data` line for notification".to_string()) + })?; + let notification = serde_json::from_str::<Notification>(&data)?; + Event::Notification(notification) + }, + "update" => { + let data = + data.ok_or_else(|| Error::Other("Missing `data` line for update".to_string()))?; + let status = serde_json::from_str::<Status>(&data)?; + Event::Update(status) + }, + "delete" => { + let data = + data.ok_or_else(|| Error::Other("Missing `data` line for delete".to_string()))?; + Event::Delete(data) + }, + "filters_changed" => Event::FiltersChanged, + _ => return Err(Error::Other(format!("Unknown event `{}`", event))), + }) + } + } + */ + + + + + + + + + + + + + + + + // Convert the HTTP response body from JSON. Pass up deserialization errors + // transparently. + + // If deserializing into the desired type fails try again to + // see if this is an error response. + use std::borrow::Cow; + use try_from::TryInto; + use crate::errors::{Error, Result}; + use crate::scopes::Scopes; + /// Represents an application that can be registered with a mastodon instance + pub struct App { + client_name: String, + redirect_uris: String, + scopes: Scopes, + #[serde(skip_serializing_if = "Option::is_none")] + website: Option<String>, + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for App { + #[inline] + fn clone(&self) -> App { + match *self { + App { + client_name: ref __self_0_0, + redirect_uris: ref __self_0_1, + scopes: ref __self_0_2, + website: ref __self_0_3 } => + App{client_name: ::core::clone::Clone::clone(&(*__self_0_0)), + redirect_uris: + ::core::clone::Clone::clone(&(*__self_0_1)), + scopes: ::core::clone::Clone::clone(&(*__self_0_2)), + website: ::core::clone::Clone::clone(&(*__self_0_3)),}, + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::fmt::Debug for App { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match *self { + App { + client_name: ref __self_0_0, + redirect_uris: ref __self_0_1, + scopes: ref __self_0_2, + website: ref __self_0_3 } => { + let mut debug_trait_builder = f.debug_struct("App"); + let _ = + debug_trait_builder.field("client_name", + &&(*__self_0_0)); + let _ = + debug_trait_builder.field("redirect_uris", + &&(*__self_0_1)); + let _ = + debug_trait_builder.field("scopes", &&(*__self_0_2)); + let _ = + debug_trait_builder.field("website", &&(*__self_0_3)); + debug_trait_builder.finish() + } + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for App { + #[inline] + fn default() -> App { + App{client_name: ::core::default::Default::default(), + redirect_uris: ::core::default::Default::default(), + scopes: ::core::default::Default::default(), + website: ::core::default::Default::default(),} + } + } + #[doc(hidden)] + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const _IMPL_SERIALIZE_FOR_App: () = + { + #[allow(rust_2018_idioms, clippy :: useless_attribute)] + extern crate serde as _serde; + #[allow(unused_macros)] + macro_rules! try { + ($ __expr : expr) => + { + match $ __expr + { + _serde :: export :: Ok(__val) => __val, _serde :: + export :: Err(__err) => + { return _serde :: export :: Err(__err) ; } + } + } + } + #[automatically_derived] + impl _serde::Serialize for App { + fn serialize<__S>(&self, __serializer: __S) + -> _serde::export::Result<__S::Ok, __S::Error> where + __S: _serde::Serializer { + let mut __serde_state = + match _serde::Serializer::serialize_struct(__serializer, + "App", + false as + usize + + 1 + 1 + + 1 + + if Option::is_none(&self.website) + { + 0 + } else { + 1 + }) { + _serde::export::Ok(__val) => __val, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + }; + match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, + "client_name", + &self.client_name) + { + _serde::export::Ok(__val) => __val, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + }; + match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, + "redirect_uris", + &self.redirect_uris) + { + _serde::export::Ok(__val) => __val, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + }; + match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, + "scopes", + &self.scopes) + { + _serde::export::Ok(__val) => __val, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + }; + if !Option::is_none(&self.website) { + match _serde::ser::SerializeStruct::serialize_field(&mut __serde_state, + "website", + &self.website) + { + _serde::export::Ok(__val) => __val, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + }; + } else { + match _serde::ser::SerializeStruct::skip_field(&mut __serde_state, + "website") + { + _serde::export::Ok(__val) => __val, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + }; + } + _serde::ser::SerializeStruct::end(__serde_state) + } + } + }; + impl ::core::marker::StructuralPartialEq for App { } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for App { + #[inline] + fn eq(&self, other: &App) -> bool { + match *other { + App { + client_name: ref __self_1_0, + redirect_uris: ref __self_1_1, + scopes: ref __self_1_2, + website: ref __self_1_3 } => + match *self { + App { + client_name: ref __self_0_0, + redirect_uris: ref __self_0_1, + scopes: ref __self_0_2, + website: ref __self_0_3 } => + (*__self_0_0) == (*__self_1_0) && + (*__self_0_1) == (*__self_1_1) && + (*__self_0_2) == (*__self_1_2) && + (*__self_0_3) == (*__self_1_3), + }, + } + } + #[inline] + fn ne(&self, other: &App) -> bool { + match *other { + App { + client_name: ref __self_1_0, + redirect_uris: ref |