From 813c7139db7de3541f0b770d2b08ad85194690ca Mon Sep 17 00:00:00 2001 From: Yoshihiro Sugi Date: Thu, 23 May 2024 11:44:13 +0900 Subject: [PATCH] feat: Generate lexicon token as const &str (#179) * Update codegen to generate lex token as const str * Update API, generated by updated codegen --- atrium-api/src/app/bsky/feed/defs.rs | 24 ++++----- atrium-api/src/app/bsky/graph/defs.rs | 4 +- atrium-api/src/com/atproto/moderation/defs.rs | 14 ++--- atrium-api/src/tools/ozone/moderation/defs.rs | 8 +-- atrium-api/src/types.rs | 51 +++++++++++++++++++ lexicon/atrium-codegen/src/generator.rs | 4 +- lexicon/atrium-codegen/src/token_stream.rs | 28 +++++----- 7 files changed, 90 insertions(+), 43 deletions(-) diff --git a/atrium-api/src/app/bsky/feed/defs.rs b/atrium-api/src/app/bsky/feed/defs.rs index 20047201..df2d63b6 100644 --- a/atrium-api/src/app/bsky/feed/defs.rs +++ b/atrium-api/src/app/bsky/feed/defs.rs @@ -15,13 +15,13 @@ pub struct BlockedPost { pub uri: String, } ///User clicked through to the author of the feed item -pub struct ClickthroughAuthor; +pub const CLICKTHROUGH_AUTHOR: &str = "app.bsky.feed.defs#clickthroughAuthor"; ///User clicked through to the embedded content of the feed item -pub struct ClickthroughEmbed; +pub const CLICKTHROUGH_EMBED: &str = "app.bsky.feed.defs#clickthroughEmbed"; ///User clicked through to the feed item -pub struct ClickthroughItem; +pub const CLICKTHROUGH_ITEM: &str = "app.bsky.feed.defs#clickthroughItem"; ///User clicked through to the reposter of the feed item -pub struct ClickthroughReposter; +pub const CLICKTHROUGH_REPOSTER: &str = "app.bsky.feed.defs#clickthroughReposter"; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct FeedViewPost { @@ -76,17 +76,17 @@ pub struct Interaction { pub item: Option, } ///User liked the feed item -pub struct InteractionLike; +pub const INTERACTION_LIKE: &str = "app.bsky.feed.defs#interactionLike"; ///User quoted the feed item -pub struct InteractionQuote; +pub const INTERACTION_QUOTE: &str = "app.bsky.feed.defs#interactionQuote"; ///User replied to the feed item -pub struct InteractionReply; +pub const INTERACTION_REPLY: &str = "app.bsky.feed.defs#interactionReply"; ///User reposted the feed item -pub struct InteractionRepost; +pub const INTERACTION_REPOST: &str = "app.bsky.feed.defs#interactionRepost"; ///Feed item was seen by user -pub struct InteractionSeen; +pub const INTERACTION_SEEN: &str = "app.bsky.feed.defs#interactionSeen"; ///User shared the feed item -pub struct InteractionShare; +pub const INTERACTION_SHARE: &str = "app.bsky.feed.defs#interactionShare"; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct NotFoundPost { @@ -132,9 +132,9 @@ pub struct ReplyRef { pub root: crate::types::Union, } ///Request that less content like the given feed item be shown in the feed -pub struct RequestLess; +pub const REQUEST_LESS: &str = "app.bsky.feed.defs#requestLess"; ///Request that more content like the given feed item be shown in the feed -pub struct RequestMore; +pub const REQUEST_MORE: &str = "app.bsky.feed.defs#requestMore"; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct SkeletonFeedPost { diff --git a/atrium-api/src/app/bsky/graph/defs.rs b/atrium-api/src/app/bsky/graph/defs.rs index acf38353..47e1ecfb 100644 --- a/atrium-api/src/app/bsky/graph/defs.rs +++ b/atrium-api/src/app/bsky/graph/defs.rs @@ -1,7 +1,7 @@ // This file is generated by atrium-codegen. DO NOT EDIT. //!Definitions for the `app.bsky.graph.defs` namespace. ///A list of actors used for curation purposes such as list feeds or interaction gating. -pub struct Curatelist; +pub const CURATELIST: &str = "app.bsky.graph.defs#curatelist"; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct ListItemView { @@ -54,7 +54,7 @@ pub struct ListViewerState { pub muted: Option, } ///A list of actors to apply an aggregate moderation action (mute/block) on. -pub struct Modlist; +pub const MODLIST: &str = "app.bsky.graph.defs#modlist"; ///indicates that a handle or DID could not be resolved #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] diff --git a/atrium-api/src/com/atproto/moderation/defs.rs b/atrium-api/src/com/atproto/moderation/defs.rs index 7d92c93d..2e33ff95 100644 --- a/atrium-api/src/com/atproto/moderation/defs.rs +++ b/atrium-api/src/com/atproto/moderation/defs.rs @@ -1,17 +1,17 @@ // This file is generated by atrium-codegen. DO NOT EDIT. //!Definitions for the `com.atproto.moderation.defs` namespace. ///Appeal: appeal a previously taken moderation action -pub struct ReasonAppeal; +pub const REASON_APPEAL: &str = "com.atproto.moderation.defs#reasonAppeal"; ///Misleading identity, affiliation, or content -pub struct ReasonMisleading; +pub const REASON_MISLEADING: &str = "com.atproto.moderation.defs#reasonMisleading"; ///Other: reports not falling under another report category -pub struct ReasonOther; +pub const REASON_OTHER: &str = "com.atproto.moderation.defs#reasonOther"; ///Rude, harassing, explicit, or otherwise unwelcoming behavior -pub struct ReasonRude; +pub const REASON_RUDE: &str = "com.atproto.moderation.defs#reasonRude"; ///Unwanted or mislabeled sexual content -pub struct ReasonSexual; +pub const REASON_SEXUAL: &str = "com.atproto.moderation.defs#reasonSexual"; ///Spam: frequent unwanted promotion, replies, mentions -pub struct ReasonSpam; +pub const REASON_SPAM: &str = "com.atproto.moderation.defs#reasonSpam"; pub type ReasonType = String; ///Direct violation of server rules, laws, terms of service -pub struct ReasonViolation; +pub const REASON_VIOLATION: &str = "com.atproto.moderation.defs#reasonViolation"; diff --git a/atrium-api/src/tools/ozone/moderation/defs.rs b/atrium-api/src/tools/ozone/moderation/defs.rs index baffbd1f..54d42577 100644 --- a/atrium-api/src/tools/ozone/moderation/defs.rs +++ b/atrium-api/src/tools/ozone/moderation/defs.rs @@ -262,13 +262,13 @@ pub struct RepoViewNotFound { pub did: crate::types::string::Did, } ///Moderator review status of a subject: Closed. Indicates that the subject was already reviewed and resolved by a moderator -pub struct ReviewClosed; +pub const REVIEW_CLOSED: &str = "tools.ozone.moderation.defs#reviewClosed"; ///Moderator review status of a subject: Escalated. Indicates that the subject was escalated for review by a moderator -pub struct ReviewEscalated; +pub const REVIEW_ESCALATED: &str = "tools.ozone.moderation.defs#reviewEscalated"; ///Moderator review status of a subject: Unnecessary. Indicates that the subject does not need a review at the moment but there is probably some moderation related metadata available for it -pub struct ReviewNone; +pub const REVIEW_NONE: &str = "tools.ozone.moderation.defs#reviewNone"; ///Moderator review status of a subject: Open. Indicates that the subject needs to be reviewed by a moderator -pub struct ReviewOpen; +pub const REVIEW_OPEN: &str = "tools.ozone.moderation.defs#reviewOpen"; pub type SubjectReviewState = String; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] diff --git a/atrium-api/src/types.rs b/atrium-api/src/types.rs index 95876b1a..dc0e1944 100644 --- a/atrium-api/src/types.rs +++ b/atrium-api/src/types.rs @@ -110,6 +110,7 @@ impl Eq for UnknownData {} mod tests { use super::*; use serde_json::{from_str, to_string}; + use std::collections::BTreeMap; const CID_LINK_JSON: &str = r#"{"$link":"bafkreibme22gw2h7y2h7tg2fhqotaqjucnbc24deqo72b6mkl2egezxhvy"}"#; @@ -198,4 +199,54 @@ mod tests { })) ); } + + #[test] + fn test_union() { + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] + #[serde(tag = "$type")] + enum FooRefs { + #[serde(rename = "example.com#bar")] + Bar(Box), + #[serde(rename = "example.com#baz")] + Baz(Box), + } + + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] + struct Bar { + bar: String, + } + + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] + struct Baz { + baz: i32, + } + + type Foo = Union; + + let foo = serde_json::from_str::(r#"{"$type":"example.com#bar","bar":"bar"}"#) + .expect("failed to deserialize foo"); + assert_eq!( + foo, + Union::Refs(FooRefs::Bar(Box::new(Bar { + bar: String::from("bar") + }))) + ); + + let foo = serde_json::from_str::(r#"{"$type":"example.com#baz","baz":42}"#) + .expect("failed to deserialize foo"); + assert_eq!(foo, Union::Refs(FooRefs::Baz(Box::new(Baz { baz: 42 })))); + + let foo = serde_json::from_str::(r#"{"$type":"example.com#foo","foo":true}"#) + .expect("failed to deserialize foo"); + assert_eq!( + foo, + Union::Unknown(UnknownData { + r#type: String::from("example.com#foo"), + data: Ipld::Map(BTreeMap::from_iter([( + String::from("foo"), + Ipld::Bool(true) + )])) + }) + ); + } } diff --git a/lexicon/atrium-codegen/src/generator.rs b/lexicon/atrium-codegen/src/generator.rs index 376309f7..edbaffa1 100644 --- a/lexicon/atrium-codegen/src/generator.rs +++ b/lexicon/atrium-codegen/src/generator.rs @@ -39,14 +39,14 @@ pub(crate) fn generate_schemas( } // main def if name == "main" { - tokens.push(user_type(def, basename, true)?); + tokens.push(user_type(def, &schema.id, basename, true)?); } else { names.push(name); } } // other defs for &name in names.iter().sorted() { - tokens.push(user_type(&schema.defs[name], name, false)?); + tokens.push(user_type(&schema.defs[name], &schema.id, name, false)?); } // ref unions tokens.push(ref_unions(&schema.id, &find_ref_unions(&schema.defs))?); diff --git a/lexicon/atrium-codegen/src/token_stream.rs b/lexicon/atrium-codegen/src/token_stream.rs index 5d285aec..358bd0d4 100644 --- a/lexicon/atrium-codegen/src/token_stream.rs +++ b/lexicon/atrium-codegen/src/token_stream.rs @@ -1,5 +1,5 @@ use atrium_lex::lexicon::*; -use heck::{ToPascalCase, ToSnakeCase}; +use heck::{ToPascalCase, ToShoutySnakeCase, ToSnakeCase}; use itertools::Itertools; use proc_macro2::TokenStream; use quote::{format_ident, quote}; @@ -13,14 +13,19 @@ enum OutputType { Bytes, } -pub fn user_type(def: &LexUserType, name: &str, is_main: bool) -> Result { +pub fn user_type( + def: &LexUserType, + schema_id: &str, + name: &str, + is_main: bool, +) -> Result { let user_type = match def { LexUserType::Record(record) => lex_record(record)?, LexUserType::XrpcQuery(query) => lex_query(query)?, LexUserType::XrpcProcedure(procedure) => lex_procedure(procedure)?, LexUserType::XrpcSubscription(subscription) => lex_subscription(subscription)?, LexUserType::Array(array) => lex_array(array, name)?, - LexUserType::Token(token) => lex_token(token, name)?, + LexUserType::Token(token) => lex_token(token, name, schema_id)?, LexUserType::Object(object) => lex_object(object, if is_main { "Main" } else { name })?, LexUserType::String(string) => lex_string(string, name)?, _ => unimplemented!("{def:?}"), @@ -245,13 +250,13 @@ fn lex_array(array: &LexArray, name: &str) -> Result { }) } -fn lex_token(token: &LexToken, name: &str) -> Result { +fn lex_token(token: &LexToken, name: &str, schema_id: &str) -> Result { let description = description(&token.description); - let token_name = format_ident!("{}", name.to_pascal_case()); - // TODO + let token_name = format_ident!("{}", name.to_shouty_snake_case()); + let token_value = format!("{schema_id}#{name}"); Ok(quote! { #description - pub struct #token_name; + pub const #token_name: &str = #token_value; }) } @@ -314,11 +319,6 @@ fn lex_object_property( LexObjectProperty::String(string) => string_type(string)?, LexObjectProperty::Unknown(unknown) => unknown_type(unknown, Some(name))?, }; - // TODO: must be determined - if field_type.is_empty() { - return Ok(quote!()); - } - // TODO: other keywords? let field_name = format_ident!( "{}", if name == "ref" || name == "type" { @@ -412,10 +412,6 @@ fn array_type( )?, _ => unimplemented!("{:?}", array.items), }; - // TODO: must be determined - if item_type.is_empty() { - return Ok((description, quote!())); - } Ok((description, quote!(Vec<#item_type>))) }