A better Rust ATProto crate

minimal auth client, plus some fixes for codegen for bytes upload and encoding

Orual aa87f30d 32f38c8a

+1403 -228
+2 -3
crates/jacquard-api/src/app_bsky/feed/get_suggested_feeds.rs
··· 50 51 impl jacquard_common::types::xrpc::XrpcRequest for GetSuggestedFeeds<'_> { 52 const NSID: &'static str = "app.bsky.feed.getSuggestedFeeds"; 53 - const METHOD: jacquard_common::types::xrpc::XrpcMethod = 54 - jacquard_common::types::xrpc::XrpcMethod::Query; 55 const OUTPUT_ENCODING: &'static str = "application/json"; 56 type Output<'de> = GetSuggestedFeedsOutput<'de>; 57 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 58 - }
··· 50 51 impl jacquard_common::types::xrpc::XrpcRequest for GetSuggestedFeeds<'_> { 52 const NSID: &'static str = "app.bsky.feed.getSuggestedFeeds"; 53 + const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Query; 54 const OUTPUT_ENCODING: &'static str = "application/json"; 55 type Output<'de> = GetSuggestedFeedsOutput<'de>; 56 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 57 + }
+2 -3
crates/jacquard-api/src/app_bsky/unspecced/get_onboarding_suggested_starter_packs.rs
··· 40 41 impl jacquard_common::types::xrpc::XrpcRequest for GetOnboardingSuggestedStarterPacks { 42 const NSID: &'static str = "app.bsky.unspecced.getOnboardingSuggestedStarterPacks"; 43 - const METHOD: jacquard_common::types::xrpc::XrpcMethod = 44 - jacquard_common::types::xrpc::XrpcMethod::Query; 45 const OUTPUT_ENCODING: &'static str = "application/json"; 46 type Output<'de> = GetOnboardingSuggestedStarterPacksOutput<'de>; 47 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 48 - }
··· 40 41 impl jacquard_common::types::xrpc::XrpcRequest for GetOnboardingSuggestedStarterPacks { 42 const NSID: &'static str = "app.bsky.unspecced.getOnboardingSuggestedStarterPacks"; 43 + const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Query; 44 const OUTPUT_ENCODING: &'static str = "application/json"; 45 type Output<'de> = GetOnboardingSuggestedStarterPacksOutput<'de>; 46 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 47 + }
+11 -8
crates/jacquard-api/src/app_bsky/video/upload_video.rs
··· 5 // This file was automatically generated from Lexicon schemas. 6 // Any manual changes will be overwritten on the next regeneration. 7 8 - #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 - pub struct UploadVideo<'a> {} 12 - impl jacquard_common::IntoStatic for UploadVideo<'_> { 13 - type Output = UploadVideo<'static>; 14 fn into_static(self) -> Self::Output { 15 - UploadVideo { 16 - extra_data: self.extra_data.into_static(), 17 - } 18 } 19 } 20 ··· 36 } 37 } 38 39 - impl jacquard_common::types::xrpc::XrpcRequest for UploadVideo<'_> { 40 const NSID: &'static str = "app.bsky.video.uploadVideo"; 41 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 42 "video/mp4", ··· 44 const OUTPUT_ENCODING: &'static str = "application/json"; 45 type Output<'de> = UploadVideoOutput<'de>; 46 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 47 }
··· 5 // This file was automatically generated from Lexicon schemas. 6 // Any manual changes will be overwritten on the next regeneration. 7 8 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 #[serde(rename_all = "camelCase")] 10 + pub struct UploadVideo { 11 + pub body: bytes::Bytes, 12 + } 13 + 14 + impl jacquard_common::IntoStatic for UploadVideo { 15 + type Output = UploadVideo; 16 fn into_static(self) -> Self::Output { 17 + self 18 } 19 } 20 ··· 36 } 37 } 38 39 + impl jacquard_common::types::xrpc::XrpcRequest for UploadVideo { 40 const NSID: &'static str = "app.bsky.video.uploadVideo"; 41 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 42 "video/mp4", ··· 44 const OUTPUT_ENCODING: &'static str = "application/json"; 45 type Output<'de> = UploadVideoOutput<'de>; 46 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 47 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 48 + Ok(self.body.to_vec()) 49 + } 50 }
+11 -8
crates/jacquard-api/src/com_atproto/repo/import_repo.rs
··· 5 // This file was automatically generated from Lexicon schemas. 6 // Any manual changes will be overwritten on the next regeneration. 7 8 - #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 - pub struct ImportRepo<'a> {} 12 - impl jacquard_common::IntoStatic for ImportRepo<'_> { 13 - type Output = ImportRepo<'static>; 14 fn into_static(self) -> Self::Output { 15 - ImportRepo { 16 - extra_data: self.extra_data.into_static(), 17 - } 18 } 19 } 20 21 - impl jacquard_common::types::xrpc::XrpcRequest for ImportRepo<'_> { 22 const NSID: &'static str = "com.atproto.repo.importRepo"; 23 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 24 "application/vnd.ipld.car", ··· 26 const OUTPUT_ENCODING: &'static str = "application/json"; 27 type Output<'de> = (); 28 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 29 }
··· 5 // This file was automatically generated from Lexicon schemas. 6 // Any manual changes will be overwritten on the next regeneration. 7 8 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 #[serde(rename_all = "camelCase")] 10 + pub struct ImportRepo { 11 + pub body: bytes::Bytes, 12 + } 13 + 14 + impl jacquard_common::IntoStatic for ImportRepo { 15 + type Output = ImportRepo; 16 fn into_static(self) -> Self::Output { 17 + self 18 } 19 } 20 21 + impl jacquard_common::types::xrpc::XrpcRequest for ImportRepo { 22 const NSID: &'static str = "com.atproto.repo.importRepo"; 23 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 24 "application/vnd.ipld.car", ··· 26 const OUTPUT_ENCODING: &'static str = "application/json"; 27 type Output<'de> = (); 28 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 29 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 30 + Ok(self.body.to_vec()) 31 + } 32 }
+11 -8
crates/jacquard-api/src/com_atproto/repo/upload_blob.rs
··· 5 // This file was automatically generated from Lexicon schemas. 6 // Any manual changes will be overwritten on the next regeneration. 7 8 - #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 - pub struct UploadBlob<'a> {} 12 - impl jacquard_common::IntoStatic for UploadBlob<'_> { 13 - type Output = UploadBlob<'static>; 14 fn into_static(self) -> Self::Output { 15 - UploadBlob { 16 - extra_data: self.extra_data.into_static(), 17 - } 18 } 19 } 20 ··· 36 } 37 } 38 39 - impl jacquard_common::types::xrpc::XrpcRequest for UploadBlob<'_> { 40 const NSID: &'static str = "com.atproto.repo.uploadBlob"; 41 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 42 "*/*", ··· 44 const OUTPUT_ENCODING: &'static str = "application/json"; 45 type Output<'de> = UploadBlobOutput<'de>; 46 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 47 }
··· 5 // This file was automatically generated from Lexicon schemas. 6 // Any manual changes will be overwritten on the next regeneration. 7 8 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 #[serde(rename_all = "camelCase")] 10 + pub struct UploadBlob { 11 + pub body: bytes::Bytes, 12 + } 13 + 14 + impl jacquard_common::IntoStatic for UploadBlob { 15 + type Output = UploadBlob; 16 fn into_static(self) -> Self::Output { 17 + self 18 } 19 } 20 ··· 36 } 37 } 38 39 + impl jacquard_common::types::xrpc::XrpcRequest for UploadBlob { 40 const NSID: &'static str = "com.atproto.repo.uploadBlob"; 41 const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure( 42 "*/*", ··· 44 const OUTPUT_ENCODING: &'static str = "application/json"; 45 type Output<'de> = UploadBlobOutput<'de>; 46 type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>; 47 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 48 + Ok(self.body.to_vec()) 49 + } 50 }
+29 -1
crates/jacquard-common/src/types/xrpc.rs
··· 1 - use serde::de::DeserializeOwned; 2 use serde::{Deserialize, Serialize}; 3 use std::error::Error; 4 use std::fmt::{self, Debug}; 5 6 use crate::IntoStatic; 7 use crate::types::value::Data; 8 9 /// XRPC method type 10 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] ··· 53 54 /// Error type for this request 55 type Err<'de>: Error + Deserialize<'de> + IntoStatic; 56 } 57 58 /// Error type for XRPC endpoints that don't define any errors
··· 1 use serde::{Deserialize, Serialize}; 2 use std::error::Error; 3 use std::fmt::{self, Debug}; 4 5 use crate::IntoStatic; 6 use crate::types::value::Data; 7 + 8 + /// Error type for encoding XRPC requests 9 + #[derive(Debug, thiserror::Error, miette::Diagnostic)] 10 + pub enum EncodeError { 11 + /// Failed to serialize query parameters 12 + #[error("Failed to serialize query: {0}")] 13 + Query( 14 + #[from] 15 + #[source] 16 + serde_html_form::ser::Error, 17 + ), 18 + /// Failed to serialize JSON body 19 + #[error("Failed to serialize JSON: {0}")] 20 + Json( 21 + #[from] 22 + #[source] 23 + serde_json::Error, 24 + ), 25 + /// Other encoding error 26 + #[error("Encoding error: {0}")] 27 + Other(String), 28 + } 29 30 /// XRPC method type 31 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] ··· 74 75 /// Error type for this request 76 type Err<'de>: Error + Deserialize<'de> + IntoStatic; 77 + 78 + /// Encode the request body for procedures. 79 + /// 80 + /// Default implementation serializes to JSON. Override for non-JSON encodings. 81 + fn encode_body(&self) -> Result<Vec<u8>, EncodeError> { 82 + Ok(serde_json::to_vec(self)?) 83 + } 84 } 85 86 /// Error type for XRPC endpoints that don't define any errors
+79 -26
crates/jacquard-lexicon/src/codegen.rs
··· 662 params_has_lifetime, 663 has_output, 664 has_errors, 665 )?; 666 output.push(xrpc_impl); 667 ··· 680 let type_base = self.def_to_type_name(nsid, def_name); 681 let mut output = Vec::new(); 682 683 - // Input bodies always have lifetimes (they get #[lexicon] attribute) 684 - let params_has_lifetime = proc.input.is_some(); 685 let has_input = proc.input.is_some(); 686 let has_output = proc.output.is_some(); 687 let has_errors = proc.errors.is_some(); ··· 726 params_has_lifetime, 727 has_output, 728 has_errors, 729 )?; 730 output.push(xrpc_impl); 731 ··· 1424 ) -> Result<TokenStream> { 1425 let ident = syn::Ident::new(type_base, proc_macro2::Span::call_site()); 1426 1427 let fields = if let Some(schema) = &body.schema { 1428 self.generate_body_fields("", type_base, schema)? 1429 } else { 1430 - quote! {} 1431 }; 1432 1433 let doc = self.generate_doc_comment(body.description.as_ref()); 1434 1435 - // Input structs always get a lifetime since they have the #[lexicon] attribute 1436 - // which adds extra_data: BTreeMap<..., Data<'a>> 1437 - let struct_def = quote! { 1438 - #doc 1439 - #[jacquard_derive::lexicon] 1440 - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 1441 - #[serde(rename_all = "camelCase")] 1442 - pub struct #ident<'a> { 1443 - #fields 1444 } 1445 }; 1446 ··· 1458 } 1459 1460 // Generate IntoStatic impl 1461 - let field_names: Vec<&str> = match &body.schema { 1462 - Some(crate::lexicon::LexXrpcBodySchema::Object(obj)) => { 1463 - obj.properties.keys().map(|k| k.as_str()).collect() 1464 - } 1465 - Some(_) => { 1466 - // For Ref or Union schemas, there's just a single flattened field 1467 - vec!["value"] 1468 - } 1469 - None => { 1470 - // No schema means no fields, just extra_data 1471 - vec![] 1472 } 1473 }; 1474 - let into_static_impl = 1475 - self.generate_into_static_for_struct(type_base, &field_names, true, true); 1476 1477 Ok(quote! { 1478 #struct_def ··· 1923 params_has_lifetime: bool, 1924 has_output: bool, 1925 has_errors: bool, 1926 ) -> Result<TokenStream> { 1927 let output_type = if has_output { 1928 let output_ident = syn::Ident::new( ··· 1944 quote! { jacquard_common::types::xrpc::GenericError<'de> } 1945 }; 1946 1947 if has_params { 1948 // Implement on the params/input struct itself 1949 let request_ident = syn::Ident::new(type_base, proc_macro2::Span::call_site()); ··· 1961 1962 type Output<'de> = #output_type; 1963 type Err<'de> = #error_type; 1964 } 1965 }) 1966 } else { ··· 2311 println!("\n{}\n", formatted); 2312 2313 // Check structure 2314 - assert!(formatted.contains("struct GetAuthorFeedParams")); 2315 assert!(formatted.contains("struct GetAuthorFeedOutput")); 2316 assert!(formatted.contains("enum GetAuthorFeedError")); 2317 assert!(formatted.contains("pub actor"));
··· 662 params_has_lifetime, 663 has_output, 664 has_errors, 665 + false, // queries never have binary inputs 666 )?; 667 output.push(xrpc_impl); 668 ··· 681 let type_base = self.def_to_type_name(nsid, def_name); 682 let mut output = Vec::new(); 683 684 + // Check if input is a binary body (no schema) 685 + let is_binary_input = proc 686 + .input 687 + .as_ref() 688 + .map(|i| i.schema.is_none()) 689 + .unwrap_or(false); 690 + 691 + // Input bodies with schemas have lifetimes (they get #[lexicon] attribute) 692 + // Binary inputs don't have lifetimes 693 + let params_has_lifetime = proc.input.is_some() && !is_binary_input; 694 let has_input = proc.input.is_some(); 695 let has_output = proc.output.is_some(); 696 let has_errors = proc.errors.is_some(); ··· 735 params_has_lifetime, 736 has_output, 737 has_errors, 738 + is_binary_input, 739 )?; 740 output.push(xrpc_impl); 741 ··· 1434 ) -> Result<TokenStream> { 1435 let ident = syn::Ident::new(type_base, proc_macro2::Span::call_site()); 1436 1437 + // Check if this is a binary body (no schema, just raw bytes) 1438 + let is_binary_body = body.schema.is_none(); 1439 + 1440 let fields = if let Some(schema) = &body.schema { 1441 self.generate_body_fields("", type_base, schema)? 1442 } else { 1443 + // Binary body: just a bytes field 1444 + quote! { 1445 + pub body: bytes::Bytes, 1446 + } 1447 }; 1448 1449 let doc = self.generate_doc_comment(body.description.as_ref()); 1450 1451 + // Binary bodies don't need #[lexicon] attribute or lifetime 1452 + let struct_def = if is_binary_body { 1453 + quote! { 1454 + #doc 1455 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 1456 + #[serde(rename_all = "camelCase")] 1457 + pub struct #ident { 1458 + #fields 1459 + } 1460 + } 1461 + } else { 1462 + // Input structs with schemas get a lifetime since they have the #[lexicon] attribute 1463 + // which adds extra_data: BTreeMap<..., Data<'a>> 1464 + quote! { 1465 + #doc 1466 + #[jacquard_derive::lexicon] 1467 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 1468 + #[serde(rename_all = "camelCase")] 1469 + pub struct #ident<'a> { 1470 + #fields 1471 + } 1472 } 1473 }; 1474 ··· 1486 } 1487 1488 // Generate IntoStatic impl 1489 + let into_static_impl = if is_binary_body { 1490 + // Binary bodies: simple clone of the Bytes field 1491 + quote! { 1492 + impl jacquard_common::IntoStatic for #ident { 1493 + type Output = #ident; 1494 + fn into_static(self) -> Self::Output { 1495 + self 1496 + } 1497 + } 1498 } 1499 + } else { 1500 + let field_names: Vec<&str> = match &body.schema { 1501 + Some(crate::lexicon::LexXrpcBodySchema::Object(obj)) => { 1502 + obj.properties.keys().map(|k| k.as_str()).collect() 1503 + } 1504 + Some(_) => { 1505 + // For Ref or Union schemas, there's just a single flattened field 1506 + vec!["value"] 1507 + } 1508 + None => { 1509 + // No schema means no fields, just extra_data 1510 + vec![] 1511 + } 1512 + }; 1513 + self.generate_into_static_for_struct(type_base, &field_names, true, true) 1514 }; 1515 1516 Ok(quote! { 1517 #struct_def ··· 1962 params_has_lifetime: bool, 1963 has_output: bool, 1964 has_errors: bool, 1965 + is_binary_input: bool, 1966 ) -> Result<TokenStream> { 1967 let output_type = if has_output { 1968 let output_ident = syn::Ident::new( ··· 1984 quote! { jacquard_common::types::xrpc::GenericError<'de> } 1985 }; 1986 1987 + // Generate encode_body() method for binary inputs 1988 + let encode_body_method = if is_binary_input { 1989 + quote! { 1990 + fn encode_body(&self) -> Result<Vec<u8>, jacquard_common::types::xrpc::EncodeError> { 1991 + Ok(self.body.to_vec()) 1992 + } 1993 + } 1994 + } else { 1995 + quote! {} 1996 + }; 1997 + 1998 if has_params { 1999 // Implement on the params/input struct itself 2000 let request_ident = syn::Ident::new(type_base, proc_macro2::Span::call_site()); ··· 2012 2013 type Output<'de> = #output_type; 2014 type Err<'de> = #error_type; 2015 + 2016 + #encode_body_method 2017 } 2018 }) 2019 } else { ··· 2364 println!("\n{}\n", formatted); 2365 2366 // Check structure 2367 + assert!(formatted.contains("struct GetAuthorFeed")); 2368 assert!(formatted.contains("struct GetAuthorFeedOutput")); 2369 assert!(formatted.contains("enum GetAuthorFeedError")); 2370 assert!(formatted.contains("pub actor"));
+6 -1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky.rs
··· 1 pub mod embed; 2 pub mod feed; 3 - pub mod richtext;
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 pub mod embed; 7 pub mod feed; 8 + pub mod richtext;
+6 -1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed.rs
··· 1 pub mod external; 2 pub mod images; 3 pub mod record; 4 pub mod record_with_media; 5 - pub mod video;
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 pub mod external; 7 pub mod images; 8 pub mod record; 9 pub mod record_with_media; 10 + pub mod video;
+77 -7
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/external.rs
··· 1 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 #[serde(rename_all = "camelCase")] 3 pub struct External<'a> { 4 pub description: jacquard_common::CowStr<'a>, 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub thumb: Option<jacquard_common::types::blob::Blob<'a>>, 7 pub title: jacquard_common::CowStr<'a>, 8 pub uri: jacquard_common::types::string::Uri<'a>, 9 } 10 ///A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). 11 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 12 #[serde(rename_all = "camelCase")] 13 - pub struct External<'a> { 14 - pub external: jacquard_common::types::value::Data<'a>, 15 } 16 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 17 #[serde(rename_all = "camelCase")] 18 pub struct View<'a> { 19 - pub external: jacquard_common::types::value::Data<'a>, 20 } 21 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 22 #[serde(rename_all = "camelCase")] 23 pub struct ViewExternal<'a> { 24 pub description: jacquard_common::CowStr<'a>, 25 - #[serde(skip_serializing_if = "Option::is_none")] 26 - pub thumb: Option<jacquard_common::types::string::Uri<'a>>, 27 pub title: jacquard_common::CowStr<'a>, 28 pub uri: jacquard_common::types::string::Uri<'a>, 29 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.embed.external 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct External<'a> { 12 + #[serde(borrow)] 13 pub description: jacquard_common::CowStr<'a>, 14 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 + #[serde(borrow)] 16 + pub thumb: std::option::Option<jacquard_common::types::blob::Blob<'a>>, 17 + #[serde(borrow)] 18 pub title: jacquard_common::CowStr<'a>, 19 + #[serde(borrow)] 20 pub uri: jacquard_common::types::string::Uri<'a>, 21 } 22 + 23 + impl jacquard_common::IntoStatic for External<'_> { 24 + type Output = External<'static>; 25 + fn into_static(self) -> Self::Output { 26 + External { 27 + description: self.description.into_static(), 28 + thumb: self.thumb.into_static(), 29 + title: self.title.into_static(), 30 + uri: self.uri.into_static(), 31 + extra_data: self.extra_data.into_static(), 32 + } 33 + } 34 + } 35 + 36 ///A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). 37 + #[jacquard_derive::lexicon] 38 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 39 #[serde(rename_all = "camelCase")] 40 + pub struct ExternalRecord<'a> { 41 + #[serde(borrow)] 42 + pub external: test_generated::app_bsky::embed::external::External<'a>, 43 } 44 + 45 + impl jacquard_common::IntoStatic for ExternalRecord<'_> { 46 + type Output = ExternalRecord<'static>; 47 + fn into_static(self) -> Self::Output { 48 + ExternalRecord { 49 + external: self.external.into_static(), 50 + extra_data: self.extra_data.into_static(), 51 + } 52 + } 53 + } 54 + 55 + #[jacquard_derive::lexicon] 56 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 57 #[serde(rename_all = "camelCase")] 58 pub struct View<'a> { 59 + #[serde(borrow)] 60 + pub external: test_generated::app_bsky::embed::external::ViewExternal<'a>, 61 + } 62 + 63 + impl jacquard_common::IntoStatic for View<'_> { 64 + type Output = View<'static>; 65 + fn into_static(self) -> Self::Output { 66 + View { 67 + external: self.external.into_static(), 68 + extra_data: self.extra_data.into_static(), 69 + } 70 + } 71 } 72 + 73 + #[jacquard_derive::lexicon] 74 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 75 #[serde(rename_all = "camelCase")] 76 pub struct ViewExternal<'a> { 77 + #[serde(borrow)] 78 pub description: jacquard_common::CowStr<'a>, 79 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 80 + #[serde(borrow)] 81 + pub thumb: std::option::Option<jacquard_common::types::string::Uri<'a>>, 82 + #[serde(borrow)] 83 pub title: jacquard_common::CowStr<'a>, 84 + #[serde(borrow)] 85 pub uri: jacquard_common::types::string::Uri<'a>, 86 } 87 + 88 + impl jacquard_common::IntoStatic for ViewExternal<'_> { 89 + type Output = ViewExternal<'static>; 90 + fn into_static(self) -> Self::Output { 91 + ViewExternal { 92 + description: self.description.into_static(), 93 + thumb: self.thumb.into_static(), 94 + title: self.title.into_static(), 95 + uri: self.uri.into_static(), 96 + extra_data: self.extra_data.into_static(), 97 + } 98 + } 99 + }
+78 -6
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/images.rs
··· 1 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 #[serde(rename_all = "camelCase")] 3 pub struct Image<'a> { 4 pub alt: jacquard_common::CowStr<'a>, 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 7 pub image: jacquard_common::types::blob::Blob<'a>, 8 } 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct Images<'a> { 12 - pub images: Vec<jacquard_common::types::value::Data<'a>>, 13 } 14 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 15 #[serde(rename_all = "camelCase")] 16 pub struct View<'a> { 17 - pub images: Vec<jacquard_common::types::value::Data<'a>>, 18 } 19 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 20 #[serde(rename_all = "camelCase")] 21 pub struct ViewImage<'a> { 22 pub alt: jacquard_common::CowStr<'a>, 23 - #[serde(skip_serializing_if = "Option::is_none")] 24 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 25 pub fullsize: jacquard_common::types::string::Uri<'a>, 26 pub thumb: jacquard_common::types::string::Uri<'a>, 27 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.embed.images 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct Image<'a> { 12 + ///Alt text description of the image, for accessibility. 13 + #[serde(borrow)] 14 pub alt: jacquard_common::CowStr<'a>, 15 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 16 + #[serde(borrow)] 17 + pub aspect_ratio: std::option::Option<jacquard_common::types::value::Data<'a>>, 18 + #[serde(borrow)] 19 pub image: jacquard_common::types::blob::Blob<'a>, 20 } 21 + 22 + impl jacquard_common::IntoStatic for Image<'_> { 23 + type Output = Image<'static>; 24 + fn into_static(self) -> Self::Output { 25 + Image { 26 + alt: self.alt.into_static(), 27 + aspect_ratio: self.aspect_ratio.into_static(), 28 + image: self.image.into_static(), 29 + extra_data: self.extra_data.into_static(), 30 + } 31 + } 32 + } 33 + 34 + #[jacquard_derive::lexicon] 35 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 36 #[serde(rename_all = "camelCase")] 37 pub struct Images<'a> { 38 + #[serde(borrow)] 39 + pub images: Vec<test_generated::app_bsky::embed::images::Image<'a>>, 40 } 41 + 42 + impl jacquard_common::IntoStatic for Images<'_> { 43 + type Output = Images<'static>; 44 + fn into_static(self) -> Self::Output { 45 + Images { 46 + images: self.images.into_static(), 47 + extra_data: self.extra_data.into_static(), 48 + } 49 + } 50 + } 51 + 52 + #[jacquard_derive::lexicon] 53 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 54 #[serde(rename_all = "camelCase")] 55 pub struct View<'a> { 56 + #[serde(borrow)] 57 + pub images: Vec<test_generated::app_bsky::embed::images::ViewImage<'a>>, 58 + } 59 + 60 + impl jacquard_common::IntoStatic for View<'_> { 61 + type Output = View<'static>; 62 + fn into_static(self) -> Self::Output { 63 + View { 64 + images: self.images.into_static(), 65 + extra_data: self.extra_data.into_static(), 66 + } 67 + } 68 } 69 + 70 + #[jacquard_derive::lexicon] 71 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 72 #[serde(rename_all = "camelCase")] 73 pub struct ViewImage<'a> { 74 + ///Alt text description of the image, for accessibility. 75 + #[serde(borrow)] 76 pub alt: jacquard_common::CowStr<'a>, 77 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 78 + #[serde(borrow)] 79 + pub aspect_ratio: std::option::Option<jacquard_common::types::value::Data<'a>>, 80 + ///Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. 81 + #[serde(borrow)] 82 pub fullsize: jacquard_common::types::string::Uri<'a>, 83 + ///Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. 84 + #[serde(borrow)] 85 pub thumb: jacquard_common::types::string::Uri<'a>, 86 } 87 + 88 + impl jacquard_common::IntoStatic for ViewImage<'_> { 89 + type Output = ViewImage<'static>; 90 + fn into_static(self) -> Self::Output { 91 + ViewImage { 92 + alt: self.alt.into_static(), 93 + aspect_ratio: self.aspect_ratio.into_static(), 94 + fullsize: self.fullsize.into_static(), 95 + thumb: self.thumb.into_static(), 96 + extra_data: self.extra_data.into_static(), 97 + } 98 + } 99 + }
+133 -14
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/record.rs
··· 1 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 #[serde(rename_all = "camelCase")] 3 pub struct Record<'a> { 4 - pub record: test_generated::com_atproto::repo::StrongRef<'a>, 5 } 6 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 7 #[serde(rename_all = "camelCase")] 8 pub struct View<'a> { 9 - pub record: RecordRecord<'a>, 10 } 11 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 12 #[serde(rename_all = "camelCase")] 13 pub struct ViewBlocked<'a> { 14 pub author: jacquard_common::types::value::Data<'a>, 15 pub blocked: bool, 16 pub uri: jacquard_common::types::string::AtUri<'a>, 17 } 18 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 19 #[serde(rename_all = "camelCase")] 20 pub struct ViewDetached<'a> { 21 pub detached: bool, 22 pub uri: jacquard_common::types::string::AtUri<'a>, 23 } 24 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 25 #[serde(rename_all = "camelCase")] 26 pub struct ViewNotFound<'a> { 27 pub not_found: bool, 28 pub uri: jacquard_common::types::string::AtUri<'a>, 29 } 30 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 31 #[serde(rename_all = "camelCase")] 32 pub struct ViewRecord<'a> { 33 pub author: jacquard_common::types::value::Data<'a>, 34 pub cid: jacquard_common::types::string::Cid<'a>, 35 - #[serde(skip_serializing_if = "Option::is_none")] 36 - pub embeds: Option<Vec<jacquard_common::types::value::Data<'a>>>, 37 pub indexed_at: jacquard_common::types::string::Datetime, 38 - #[serde(skip_serializing_if = "Option::is_none")] 39 - pub labels: Option<Vec<test_generated::com_atproto::label::Label<'a>>>, 40 - #[serde(skip_serializing_if = "Option::is_none")] 41 - pub like_count: Option<i64>, 42 - #[serde(skip_serializing_if = "Option::is_none")] 43 - pub quote_count: Option<i64>, 44 - #[serde(skip_serializing_if = "Option::is_none")] 45 - pub reply_count: Option<i64>, 46 - #[serde(skip_serializing_if = "Option::is_none")] 47 - pub repost_count: Option<i64>, 48 pub uri: jacquard_common::types::string::AtUri<'a>, 49 pub value: jacquard_common::types::value::Data<'a>, 50 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.embed.record 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct Record<'a> { 12 + #[serde(borrow)] 13 + pub record: test_generated::com_atproto::repo::strong_ref::StrongRef<'a>, 14 + } 15 + 16 + impl jacquard_common::IntoStatic for Record<'_> { 17 + type Output = Record<'static>; 18 + fn into_static(self) -> Self::Output { 19 + Record { 20 + record: self.record.into_static(), 21 + extra_data: self.extra_data.into_static(), 22 + } 23 + } 24 } 25 + 26 + #[jacquard_derive::lexicon] 27 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 28 #[serde(rename_all = "camelCase")] 29 pub struct View<'a> { 30 + #[serde(borrow)] 31 + pub record: ViewRecordRecord<'a>, 32 } 33 + 34 + #[jacquard_derive::open_union] 35 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 36 + #[serde(tag = "$type")] 37 + #[serde(bound(deserialize = "'de: 'a"))] 38 + pub enum ViewRecordRecord<'a> {} 39 + impl jacquard_common::IntoStatic for ViewRecordRecord<'_> { 40 + type Output = ViewRecordRecord<'static>; 41 + fn into_static(self) -> Self::Output { 42 + match self { 43 + ViewRecordRecord::Unknown(v) => ViewRecordRecord::Unknown(v.into_static()), 44 + } 45 + } 46 + } 47 + 48 + impl jacquard_common::IntoStatic for View<'_> { 49 + type Output = View<'static>; 50 + fn into_static(self) -> Self::Output { 51 + View { 52 + record: self.record.into_static(), 53 + extra_data: self.extra_data.into_static(), 54 + } 55 + } 56 + } 57 + 58 + #[jacquard_derive::lexicon] 59 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 60 #[serde(rename_all = "camelCase")] 61 pub struct ViewBlocked<'a> { 62 + #[serde(borrow)] 63 pub author: jacquard_common::types::value::Data<'a>, 64 pub blocked: bool, 65 + #[serde(borrow)] 66 pub uri: jacquard_common::types::string::AtUri<'a>, 67 } 68 + 69 + impl jacquard_common::IntoStatic for ViewBlocked<'_> { 70 + type Output = ViewBlocked<'static>; 71 + fn into_static(self) -> Self::Output { 72 + ViewBlocked { 73 + author: self.author.into_static(), 74 + blocked: self.blocked.into_static(), 75 + uri: self.uri.into_static(), 76 + extra_data: self.extra_data.into_static(), 77 + } 78 + } 79 + } 80 + 81 + #[jacquard_derive::lexicon] 82 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 83 #[serde(rename_all = "camelCase")] 84 pub struct ViewDetached<'a> { 85 pub detached: bool, 86 + #[serde(borrow)] 87 pub uri: jacquard_common::types::string::AtUri<'a>, 88 } 89 + 90 + impl jacquard_common::IntoStatic for ViewDetached<'_> { 91 + type Output = ViewDetached<'static>; 92 + fn into_static(self) -> Self::Output { 93 + ViewDetached { 94 + detached: self.detached.into_static(), 95 + uri: self.uri.into_static(), 96 + extra_data: self.extra_data.into_static(), 97 + } 98 + } 99 + } 100 + 101 + #[jacquard_derive::lexicon] 102 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 103 #[serde(rename_all = "camelCase")] 104 pub struct ViewNotFound<'a> { 105 pub not_found: bool, 106 + #[serde(borrow)] 107 pub uri: jacquard_common::types::string::AtUri<'a>, 108 } 109 + 110 + impl jacquard_common::IntoStatic for ViewNotFound<'_> { 111 + type Output = ViewNotFound<'static>; 112 + fn into_static(self) -> Self::Output { 113 + ViewNotFound { 114 + not_found: self.not_found.into_static(), 115 + uri: self.uri.into_static(), 116 + extra_data: self.extra_data.into_static(), 117 + } 118 + } 119 + } 120 + 121 + #[jacquard_derive::lexicon] 122 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 123 #[serde(rename_all = "camelCase")] 124 pub struct ViewRecord<'a> { 125 + #[serde(borrow)] 126 pub author: jacquard_common::types::value::Data<'a>, 127 + #[serde(borrow)] 128 pub cid: jacquard_common::types::string::Cid<'a>, 129 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 130 + #[serde(borrow)] 131 + pub embeds: std::option::Option<Vec<jacquard_common::types::value::Data<'a>>>, 132 pub indexed_at: jacquard_common::types::string::Datetime, 133 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 134 + #[serde(borrow)] 135 + pub labels: std::option::Option<Vec<test_generated::com_atproto::label::Label<'a>>>, 136 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 137 + pub like_count: std::option::Option<i64>, 138 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 139 + pub quote_count: std::option::Option<i64>, 140 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 141 + pub reply_count: std::option::Option<i64>, 142 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 143 + pub repost_count: std::option::Option<i64>, 144 + #[serde(borrow)] 145 pub uri: jacquard_common::types::string::AtUri<'a>, 146 + ///The record data itself. 147 + #[serde(borrow)] 148 pub value: jacquard_common::types::value::Data<'a>, 149 } 150 + 151 + impl jacquard_common::IntoStatic for ViewRecord<'_> { 152 + type Output = ViewRecord<'static>; 153 + fn into_static(self) -> Self::Output { 154 + ViewRecord { 155 + author: self.author.into_static(), 156 + cid: self.cid.into_static(), 157 + embeds: self.embeds.into_static(), 158 + indexed_at: self.indexed_at.into_static(), 159 + labels: self.labels.into_static(), 160 + like_count: self.like_count.into_static(), 161 + quote_count: self.quote_count.into_static(), 162 + reply_count: self.reply_count.into_static(), 163 + repost_count: self.repost_count.into_static(), 164 + uri: self.uri.into_static(), 165 + value: self.value.into_static(), 166 + extra_data: self.extra_data.into_static(), 167 + } 168 + } 169 + }
+102 -4
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/record_with_media.rs
··· 1 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 #[serde(rename_all = "camelCase")] 3 pub struct RecordWithMedia<'a> { 4 - pub media: RecordMedia<'a>, 5 - pub record: test_generated::app_bsky::embed::Record<'a>, 6 } 7 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 #[serde(rename_all = "camelCase")] 9 pub struct View<'a> { 10 - pub media: RecordMedia<'a>, 11 - pub record: test_generated::app_bsky::embed::View<'a>, 12 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.embed.recordWithMedia 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct RecordWithMedia<'a> { 12 + #[serde(borrow)] 13 + pub media: RecordWithMediaRecordMedia<'a>, 14 + #[serde(borrow)] 15 + pub record: test_generated::app_bsky::embed::record::Record<'a>, 16 } 17 + 18 + #[jacquard_derive::open_union] 19 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 20 + #[serde(tag = "$type")] 21 + #[serde(bound(deserialize = "'de: 'a"))] 22 + pub enum RecordWithMediaRecordMedia<'a> { 23 + #[serde(rename = "app.bsky.embed.images")] 24 + Images(Box<test_generated::app_bsky::embed::images::Images<'a>>), 25 + #[serde(rename = "app.bsky.embed.video")] 26 + Video(Box<test_generated::app_bsky::embed::video::Video<'a>>), 27 + #[serde(rename = "app.bsky.embed.external")] 28 + External(Box<test_generated::app_bsky::embed::external::ExternalRecord<'a>>), 29 + } 30 + 31 + impl jacquard_common::IntoStatic for RecordWithMediaRecordMedia<'_> { 32 + type Output = RecordWithMediaRecordMedia<'static>; 33 + fn into_static(self) -> Self::Output { 34 + match self { 35 + RecordWithMediaRecordMedia::Images(v) => { 36 + RecordWithMediaRecordMedia::Images(v.into_static()) 37 + } 38 + RecordWithMediaRecordMedia::Video(v) => { 39 + RecordWithMediaRecordMedia::Video(v.into_static()) 40 + } 41 + RecordWithMediaRecordMedia::External(v) => { 42 + RecordWithMediaRecordMedia::External(v.into_static()) 43 + } 44 + RecordWithMediaRecordMedia::Unknown(v) => { 45 + RecordWithMediaRecordMedia::Unknown(v.into_static()) 46 + } 47 + } 48 + } 49 + } 50 + 51 + impl jacquard_common::IntoStatic for RecordWithMedia<'_> { 52 + type Output = RecordWithMedia<'static>; 53 + fn into_static(self) -> Self::Output { 54 + RecordWithMedia { 55 + media: self.media.into_static(), 56 + record: self.record.into_static(), 57 + extra_data: self.extra_data.into_static(), 58 + } 59 + } 60 + } 61 + 62 + #[jacquard_derive::lexicon] 63 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 64 #[serde(rename_all = "camelCase")] 65 pub struct View<'a> { 66 + #[serde(borrow)] 67 + pub media: ViewRecordMedia<'a>, 68 + #[serde(borrow)] 69 + pub record: test_generated::app_bsky::embed::record::View<'a>, 70 + } 71 + 72 + #[jacquard_derive::open_union] 73 + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 74 + #[serde(tag = "$type")] 75 + #[serde(bound(deserialize = "'de: 'a"))] 76 + pub enum ViewRecordMedia<'a> { 77 + #[serde(rename = "app.bsky.embed.images#view")] 78 + ImagesView(Box<test_generated::app_bsky::embed::images::View<'a>>), 79 + #[serde(rename = "app.bsky.embed.video#view")] 80 + VideoView(Box<test_generated::app_bsky::embed::video::View<'a>>), 81 + #[serde(rename = "app.bsky.embed.external#view")] 82 + ExternalView(Box<test_generated::app_bsky::embed::external::View<'a>>), 83 + } 84 + 85 + impl jacquard_common::IntoStatic for ViewRecordMedia<'_> { 86 + type Output = ViewRecordMedia<'static>; 87 + fn into_static(self) -> Self::Output { 88 + match self { 89 + ViewRecordMedia::ImagesView(v) => { 90 + ViewRecordMedia::ImagesView(v.into_static()) 91 + } 92 + ViewRecordMedia::VideoView(v) => ViewRecordMedia::VideoView(v.into_static()), 93 + ViewRecordMedia::ExternalView(v) => { 94 + ViewRecordMedia::ExternalView(v.into_static()) 95 + } 96 + ViewRecordMedia::Unknown(v) => ViewRecordMedia::Unknown(v.into_static()), 97 + } 98 + } 99 } 100 + 101 + impl jacquard_common::IntoStatic for View<'_> { 102 + type Output = View<'static>; 103 + fn into_static(self) -> Self::Output { 104 + View { 105 + media: self.media.into_static(), 106 + record: self.record.into_static(), 107 + extra_data: self.extra_data.into_static(), 108 + } 109 + } 110 + }
+76 -12
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/video.rs
··· 1 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 #[serde(rename_all = "camelCase")] 3 pub struct Caption<'a> { 4 pub file: jacquard_common::types::blob::Blob<'a>, 5 pub lang: jacquard_common::types::string::Language, 6 } 7 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 8 #[serde(rename_all = "camelCase")] 9 pub struct Video<'a> { 10 - #[serde(skip_serializing_if = "Option::is_none")] 11 - pub alt: Option<jacquard_common::CowStr<'a>>, 12 - #[serde(skip_serializing_if = "Option::is_none")] 13 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 14 - #[serde(skip_serializing_if = "Option::is_none")] 15 - pub captions: Option<Vec<jacquard_common::types::value::Data<'a>>>, 16 pub video: jacquard_common::types::blob::Blob<'a>, 17 } 18 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 19 #[serde(rename_all = "camelCase")] 20 pub struct View<'a> { 21 - #[serde(skip_serializing_if = "Option::is_none")] 22 - pub alt: Option<jacquard_common::CowStr<'a>>, 23 - #[serde(skip_serializing_if = "Option::is_none")] 24 - pub aspect_ratio: Option<jacquard_common::types::value::Data<'a>>, 25 pub cid: jacquard_common::types::string::Cid<'a>, 26 pub playlist: jacquard_common::types::string::Uri<'a>, 27 - #[serde(skip_serializing_if = "Option::is_none")] 28 - pub thumbnail: Option<jacquard_common::types::string::Uri<'a>>, 29 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.embed.video 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct Caption<'a> { 12 + #[serde(borrow)] 13 pub file: jacquard_common::types::blob::Blob<'a>, 14 pub lang: jacquard_common::types::string::Language, 15 } 16 + 17 + impl jacquard_common::IntoStatic for Caption<'_> { 18 + type Output = Caption<'static>; 19 + fn into_static(self) -> Self::Output { 20 + Caption { 21 + file: self.file.into_static(), 22 + lang: self.lang.into_static(), 23 + extra_data: self.extra_data.into_static(), 24 + } 25 + } 26 + } 27 + 28 + #[jacquard_derive::lexicon] 29 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 30 #[serde(rename_all = "camelCase")] 31 pub struct Video<'a> { 32 + ///Alt text description of the video, for accessibility. 33 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 34 + #[serde(borrow)] 35 + pub alt: std::option::Option<jacquard_common::CowStr<'a>>, 36 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 37 + #[serde(borrow)] 38 + pub aspect_ratio: std::option::Option<jacquard_common::types::value::Data<'a>>, 39 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 40 + #[serde(borrow)] 41 + pub captions: std::option::Option< 42 + Vec<test_generated::app_bsky::embed::video::Caption<'a>>, 43 + >, 44 + ///The mp4 video file. May be up to 100mb, formerly limited to 50mb. 45 + #[serde(borrow)] 46 pub video: jacquard_common::types::blob::Blob<'a>, 47 } 48 + 49 + impl jacquard_common::IntoStatic for Video<'_> { 50 + type Output = Video<'static>; 51 + fn into_static(self) -> Self::Output { 52 + Video { 53 + alt: self.alt.into_static(), 54 + aspect_ratio: self.aspect_ratio.into_static(), 55 + captions: self.captions.into_static(), 56 + video: self.video.into_static(), 57 + extra_data: self.extra_data.into_static(), 58 + } 59 + } 60 + } 61 + 62 + #[jacquard_derive::lexicon] 63 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 64 #[serde(rename_all = "camelCase")] 65 pub struct View<'a> { 66 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 67 + #[serde(borrow)] 68 + pub alt: std::option::Option<jacquard_common::CowStr<'a>>, 69 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 70 + #[serde(borrow)] 71 + pub aspect_ratio: std::option::Option<jacquard_common::types::value::Data<'a>>, 72 + #[serde(borrow)] 73 pub cid: jacquard_common::types::string::Cid<'a>, 74 + #[serde(borrow)] 75 pub playlist: jacquard_common::types::string::Uri<'a>, 76 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 77 + #[serde(borrow)] 78 + pub thumbnail: std::option::Option<jacquard_common::types::string::Uri<'a>>, 79 } 80 + 81 + impl jacquard_common::IntoStatic for View<'_> { 82 + type Output = View<'static>; 83 + fn into_static(self) -> Self::Output { 84 + View { 85 + alt: self.alt.into_static(), 86 + aspect_ratio: self.aspect_ratio.into_static(), 87 + cid: self.cid.into_static(), 88 + playlist: self.playlist.into_static(), 89 + thumbnail: self.thumbnail.into_static(), 90 + extra_data: self.extra_data.into_static(), 91 + } 92 + } 93 + }
+6 -1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed.rs
··· 1 pub mod get_author_feed; 2 - pub mod post;
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 pub mod get_author_feed; 7 + pub mod post;
+86 -15
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed/get_author_feed.rs
··· 1 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 #[serde(rename_all = "camelCase")] 3 - pub struct GetAuthorFeedParams<'a> { 4 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub cursor: Option<jacquard_common::CowStr<'a>>, 7 - #[serde(skip_serializing_if = "Option::is_none")] 8 - pub filter: Option<jacquard_common::CowStr<'a>>, 9 - #[serde(skip_serializing_if = "Option::is_none")] 10 - pub include_pins: Option<bool>, 11 - #[serde(skip_serializing_if = "Option::is_none")] 12 - pub limit: Option<i64>, 13 } 14 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 15 #[serde(rename_all = "camelCase")] 16 pub struct GetAuthorFeedOutput<'a> { 17 - #[serde(skip_serializing_if = "Option::is_none")] 18 - pub cursor: Option<jacquard_common::CowStr<'a>>, 19 pub feed: Vec<jacquard_common::types::value::Data<'a>>, 20 } 21 #[derive( 22 serde::Serialize, 23 serde::Deserialize, ··· 29 miette::Diagnostic 30 )] 31 #[serde(tag = "error", content = "message")] 32 - pub enum GetAuthorFeedError { 33 #[serde(rename = "BlockedActor")] 34 - BlockedActor(Option<jacquard_common::CowStr<'static>>), 35 #[serde(rename = "BlockedByActor")] 36 - BlockedByActor(Option<jacquard_common::CowStr<'static>>), 37 } 38 - impl std::fmt::Display for GetAuthorFeedError { 39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 40 match self { 41 Self::BlockedActor(msg) => { ··· 52 } 53 Ok(()) 54 } 55 } 56 } 57 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.feed.getAuthorFeed 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 9 #[serde(rename_all = "camelCase")] 10 + pub struct GetAuthorFeed<'a> { 11 + #[serde(borrow)] 12 pub actor: jacquard_common::types::ident::AtIdentifier<'a>, 13 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 14 + #[serde(borrow)] 15 + pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 16 + ///(default: "posts_with_replies") 17 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 + #[serde(borrow)] 19 + pub filter: std::option::Option<jacquard_common::CowStr<'a>>, 20 + ///(default: false) 21 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 22 + pub include_pins: std::option::Option<bool>, 23 + ///(default: 50, min: 1, max: 100) 24 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 25 + pub limit: std::option::Option<i64>, 26 + } 27 + 28 + impl jacquard_common::IntoStatic for GetAuthorFeed<'_> { 29 + type Output = GetAuthorFeed<'static>; 30 + fn into_static(self) -> Self::Output { 31 + GetAuthorFeed { 32 + actor: self.actor.into_static(), 33 + cursor: self.cursor.into_static(), 34 + filter: self.filter.into_static(), 35 + include_pins: self.include_pins.into_static(), 36 + limit: self.limit.into_static(), 37 + } 38 + } 39 } 40 + 41 + #[jacquard_derive::lexicon] 42 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 43 #[serde(rename_all = "camelCase")] 44 pub struct GetAuthorFeedOutput<'a> { 45 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 46 + #[serde(borrow)] 47 + pub cursor: std::option::Option<jacquard_common::CowStr<'a>>, 48 + #[serde(borrow)] 49 pub feed: Vec<jacquard_common::types::value::Data<'a>>, 50 } 51 + 52 + impl jacquard_common::IntoStatic for GetAuthorFeedOutput<'_> { 53 + type Output = GetAuthorFeedOutput<'static>; 54 + fn into_static(self) -> Self::Output { 55 + GetAuthorFeedOutput { 56 + cursor: self.cursor.into_static(), 57 + feed: self.feed.into_static(), 58 + extra_data: self.extra_data.into_static(), 59 + } 60 + } 61 + } 62 + 63 + #[jacquard_derive::open_union] 64 #[derive( 65 serde::Serialize, 66 serde::Deserialize, ··· 72 miette::Diagnostic 73 )] 74 #[serde(tag = "error", content = "message")] 75 + #[serde(bound(deserialize = "'de: 'a"))] 76 + pub enum GetAuthorFeedError<'a> { 77 #[serde(rename = "BlockedActor")] 78 + BlockedActor(std::option::Option<String>), 79 #[serde(rename = "BlockedByActor")] 80 + BlockedByActor(std::option::Option<String>), 81 } 82 + 83 + impl std::fmt::Display for GetAuthorFeedError<'_> { 84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 85 match self { 86 Self::BlockedActor(msg) => { ··· 97 } 98 Ok(()) 99 } 100 + Self::Unknown(err) => write!(f, "Unknown error: {:?}", err), 101 } 102 } 103 } 104 + 105 + impl jacquard_common::IntoStatic for GetAuthorFeedError<'_> { 106 + type Output = GetAuthorFeedError<'static>; 107 + fn into_static(self) -> Self::Output { 108 + match self { 109 + GetAuthorFeedError::BlockedActor(v) => { 110 + GetAuthorFeedError::BlockedActor(v.into_static()) 111 + } 112 + GetAuthorFeedError::BlockedByActor(v) => { 113 + GetAuthorFeedError::BlockedByActor(v.into_static()) 114 + } 115 + GetAuthorFeedError::Unknown(v) => { 116 + GetAuthorFeedError::Unknown(v.into_static()) 117 + } 118 + } 119 + } 120 + } 121 + 122 + impl jacquard_common::types::xrpc::XrpcRequest for GetAuthorFeed<'_> { 123 + const NSID: &'static str = "app.bsky.feed.getAuthorFeed"; 124 + const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Query; 125 + const OUTPUT_ENCODING: &'static str = "application/json"; 126 + type Output<'de> = GetAuthorFeedOutput<'de>; 127 + type Err<'de> = GetAuthorFeedError<'de>; 128 + }
+152 -25
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed/post.rs
··· 1 ///Deprecated: use facets instead. 2 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 3 #[serde(rename_all = "camelCase")] 4 pub struct Entity<'a> { 5 - pub index: jacquard_common::types::value::Data<'a>, 6 pub r#type: jacquard_common::CowStr<'a>, 7 pub value: jacquard_common::CowStr<'a>, 8 } 9 ///Record containing a Bluesky post. 10 #[jacquard_derive::lexicon] 11 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 12 #[serde(rename_all = "camelCase")] 13 pub struct Post<'a> { 14 pub created_at: jacquard_common::types::string::Datetime, 15 - #[serde(skip_serializing_if = "Option::is_none")] 16 - pub embed: Option<RecordEmbed<'a>>, 17 - #[serde(skip_serializing_if = "Option::is_none")] 18 - pub entities: Option<Vec<jacquard_common::types::value::Data<'a>>>, 19 - #[serde(skip_serializing_if = "Option::is_none")] 20 - pub facets: Option<Vec<test_generated::app_bsky::richtext::Facet<'a>>>, 21 - #[serde(skip_serializing_if = "Option::is_none")] 22 - pub labels: Option<RecordLabels<'a>>, 23 - #[serde(skip_serializing_if = "Option::is_none")] 24 - pub langs: Option<Vec<jacquard_common::types::string::Language>>, 25 - #[serde(skip_serializing_if = "Option::is_none")] 26 - pub reply: Option<jacquard_common::types::value::Data<'a>>, 27 - #[serde(skip_serializing_if = "Option::is_none")] 28 - pub tags: Option<Vec<jacquard_common::CowStr<'a>>>, 29 pub text: jacquard_common::CowStr<'a>, 30 } 31 #[jacquard_derive::open_union] 32 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 33 #[serde(tag = "$type")] 34 - pub enum RecordEmbed<'a> { 35 #[serde(rename = "app.bsky.embed.images")] 36 - Images(Box<test_generated::app_bsky::embed::Images<'a>>), 37 #[serde(rename = "app.bsky.embed.video")] 38 - Video(Box<test_generated::app_bsky::embed::Video<'a>>), 39 #[serde(rename = "app.bsky.embed.external")] 40 - External(Box<test_generated::app_bsky::embed::External<'a>>), 41 #[serde(rename = "app.bsky.embed.record")] 42 - Record(Box<test_generated::app_bsky::embed::Record<'a>>), 43 #[serde(rename = "app.bsky.embed.recordWithMedia")] 44 - RecordWithMedia(Box<test_generated::app_bsky::embed::RecordWithMedia<'a>>), 45 } 46 #[jacquard_derive::open_union] 47 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 48 #[serde(tag = "$type")] 49 - pub enum RecordLabels<'a> { 50 #[serde(rename = "com.atproto.label.defs#selfLabels")] 51 - SelfLabels(Box<test_generated::com_atproto::label::SelfLabels<'a>>), 52 } 53 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 54 #[serde(rename_all = "camelCase")] 55 pub struct ReplyRef<'a> { 56 - pub parent: test_generated::com_atproto::repo::StrongRef<'a>, 57 - pub root: test_generated::com_atproto::repo::StrongRef<'a>, 58 } 59 ///Deprecated. Use app.bsky.richtext instead -- A text segment. Start is inclusive, end is exclusive. Indices are for utf16-encoded strings. 60 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 61 #[serde(rename_all = "camelCase")] 62 pub struct TextSlice<'a> { 63 pub end: i64, 64 pub start: i64, 65 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.feed.post 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 ///Deprecated: use facets instead. 9 + #[jacquard_derive::lexicon] 10 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 11 #[serde(rename_all = "camelCase")] 12 pub struct Entity<'a> { 13 + #[serde(borrow)] 14 + pub index: test_generated::app_bsky::feed::post::TextSlice<'a>, 15 + ///Expected values are 'mention' and 'link'. 16 + #[serde(borrow)] 17 pub r#type: jacquard_common::CowStr<'a>, 18 + #[serde(borrow)] 19 pub value: jacquard_common::CowStr<'a>, 20 } 21 + 22 + impl jacquard_common::IntoStatic for Entity<'_> { 23 + type Output = Entity<'static>; 24 + fn into_static(self) -> Self::Output { 25 + Entity { 26 + index: self.index.into_static(), 27 + r#type: self.r#type.into_static(), 28 + value: self.value.into_static(), 29 + extra_data: self.extra_data.into_static(), 30 + } 31 + } 32 + } 33 + 34 ///Record containing a Bluesky post. 35 #[jacquard_derive::lexicon] 36 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 37 #[serde(rename_all = "camelCase")] 38 pub struct Post<'a> { 39 + ///Client-declared timestamp when this post was originally created. 40 pub created_at: jacquard_common::types::string::Datetime, 41 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 42 + #[serde(borrow)] 43 + pub embed: std::option::Option<PostRecordEmbed<'a>>, 44 + ///DEPRECATED: replaced by app.bsky.richtext.facet. 45 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 46 + #[serde(borrow)] 47 + pub entities: std::option::Option< 48 + Vec<test_generated::app_bsky::feed::post::Entity<'a>>, 49 + >, 50 + ///Annotations of text (mentions, URLs, hashtags, etc) 51 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 52 + #[serde(borrow)] 53 + pub facets: std::option::Option< 54 + Vec<test_generated::app_bsky::richtext::facet::Facet<'a>>, 55 + >, 56 + ///Self-label values for this post. Effectively content warnings. 57 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 58 + #[serde(borrow)] 59 + pub labels: std::option::Option<PostRecordLabels<'a>>, 60 + ///Indicates human language of post primary text content. 61 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 62 + pub langs: std::option::Option<Vec<jacquard_common::types::string::Language>>, 63 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 64 + #[serde(borrow)] 65 + pub reply: std::option::Option<test_generated::app_bsky::feed::post::ReplyRef<'a>>, 66 + ///Additional hashtags, in addition to any included in post text and facets. 67 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 68 + #[serde(borrow)] 69 + pub tags: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 70 + ///The primary post content. May be an empty string, if there are embeds. 71 + #[serde(borrow)] 72 pub text: jacquard_common::CowStr<'a>, 73 } 74 + 75 #[jacquard_derive::open_union] 76 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 77 #[serde(tag = "$type")] 78 + #[serde(bound(deserialize = "'de: 'a"))] 79 + pub enum PostRecordEmbed<'a> { 80 #[serde(rename = "app.bsky.embed.images")] 81 + Images(Box<test_generated::app_bsky::embed::images::Images<'a>>), 82 #[serde(rename = "app.bsky.embed.video")] 83 + Video(Box<test_generated::app_bsky::embed::video::Video<'a>>), 84 #[serde(rename = "app.bsky.embed.external")] 85 + External(Box<test_generated::app_bsky::embed::external::ExternalRecord<'a>>), 86 #[serde(rename = "app.bsky.embed.record")] 87 + Record(Box<test_generated::app_bsky::embed::record::Record<'a>>), 88 #[serde(rename = "app.bsky.embed.recordWithMedia")] 89 + RecordWithMedia( 90 + Box<test_generated::app_bsky::embed::record_with_media::RecordWithMedia<'a>>, 91 + ), 92 + } 93 + 94 + impl jacquard_common::IntoStatic for PostRecordEmbed<'_> { 95 + type Output = PostRecordEmbed<'static>; 96 + fn into_static(self) -> Self::Output { 97 + match self { 98 + PostRecordEmbed::Images(v) => PostRecordEmbed::Images(v.into_static()), 99 + PostRecordEmbed::Video(v) => PostRecordEmbed::Video(v.into_static()), 100 + PostRecordEmbed::External(v) => PostRecordEmbed::External(v.into_static()), 101 + PostRecordEmbed::Record(v) => PostRecordEmbed::Record(v.into_static()), 102 + PostRecordEmbed::RecordWithMedia(v) => { 103 + PostRecordEmbed::RecordWithMedia(v.into_static()) 104 + } 105 + PostRecordEmbed::Unknown(v) => PostRecordEmbed::Unknown(v.into_static()), 106 + } 107 + } 108 } 109 + 110 #[jacquard_derive::open_union] 111 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 112 #[serde(tag = "$type")] 113 + #[serde(bound(deserialize = "'de: 'a"))] 114 + pub enum PostRecordLabels<'a> { 115 #[serde(rename = "com.atproto.label.defs#selfLabels")] 116 + DefsSelfLabels(Box<test_generated::com_atproto::label::SelfLabels<'a>>), 117 } 118 + 119 + impl jacquard_common::IntoStatic for PostRecordLabels<'_> { 120 + type Output = PostRecordLabels<'static>; 121 + fn into_static(self) -> Self::Output { 122 + match self { 123 + PostRecordLabels::DefsSelfLabels(v) => { 124 + PostRecordLabels::DefsSelfLabels(v.into_static()) 125 + } 126 + PostRecordLabels::Unknown(v) => PostRecordLabels::Unknown(v.into_static()), 127 + } 128 + } 129 + } 130 + 131 + impl jacquard_common::types::collection::Collection for Post<'_> { 132 + const NSID: &'static str = "app.bsky.feed.post"; 133 + } 134 + 135 + impl jacquard_common::IntoStatic for Post<'_> { 136 + type Output = Post<'static>; 137 + fn into_static(self) -> Self::Output { 138 + Post { 139 + created_at: self.created_at.into_static(), 140 + embed: self.embed.into_static(), 141 + entities: self.entities.into_static(), 142 + facets: self.facets.into_static(), 143 + labels: self.labels.into_static(), 144 + langs: self.langs.into_static(), 145 + reply: self.reply.into_static(), 146 + tags: self.tags.into_static(), 147 + text: self.text.into_static(), 148 + extra_data: self.extra_data.into_static(), 149 + } 150 + } 151 + } 152 + 153 + #[jacquard_derive::lexicon] 154 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 155 #[serde(rename_all = "camelCase")] 156 pub struct ReplyRef<'a> { 157 + #[serde(borrow)] 158 + pub parent: test_generated::com_atproto::repo::strong_ref::StrongRef<'a>, 159 + #[serde(borrow)] 160 + pub root: test_generated::com_atproto::repo::strong_ref::StrongRef<'a>, 161 } 162 + 163 + impl jacquard_common::IntoStatic for ReplyRef<'_> { 164 + type Output = ReplyRef<'static>; 165 + fn into_static(self) -> Self::Output { 166 + ReplyRef { 167 + parent: self.parent.into_static(), 168 + root: self.root.into_static(), 169 + extra_data: self.extra_data.into_static(), 170 + } 171 + } 172 + } 173 + 174 ///Deprecated. Use app.bsky.richtext instead -- A text segment. Start is inclusive, end is exclusive. Indices are for utf16-encoded strings. 175 + #[jacquard_derive::lexicon] 176 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 177 #[serde(rename_all = "camelCase")] 178 pub struct TextSlice<'a> { 179 pub end: i64, 180 pub start: i64, 181 } 182 + 183 + impl jacquard_common::IntoStatic for TextSlice<'_> { 184 + type Output = TextSlice<'static>; 185 + fn into_static(self) -> Self::Output { 186 + TextSlice { 187 + end: self.end.into_static(), 188 + start: self.start.into_static(), 189 + extra_data: self.extra_data.into_static(), 190 + } 191 + } 192 + }
+6 -1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/richtext.rs
··· 1 - pub mod facet;
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod facet;
+74 -1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/richtext/facet.rs
··· 1 ///Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. 2 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 3 #[serde(rename_all = "camelCase")] 4 pub struct ByteSlice<'a> { 5 pub byte_end: i64, 6 pub byte_start: i64, 7 } 8 ///Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct Link<'a> { 12 pub uri: jacquard_common::types::string::Uri<'a>, 13 } 14 ///Annotation of a sub-string within rich text. 15 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 16 #[serde(rename_all = "camelCase")] 17 pub struct Facet<'a> { 18 pub features: Vec<jacquard_common::types::value::Data<'a>>, 19 - pub index: jacquard_common::types::value::Data<'a>, 20 } 21 ///Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID. 22 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 23 #[serde(rename_all = "camelCase")] 24 pub struct Mention<'a> { 25 pub did: jacquard_common::types::string::Did<'a>, 26 } 27 ///Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). 28 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 29 #[serde(rename_all = "camelCase")] 30 pub struct Tag<'a> { 31 pub tag: jacquard_common::CowStr<'a>, 32 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: app.bsky.richtext.facet 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 ///Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. 9 + #[jacquard_derive::lexicon] 10 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 11 #[serde(rename_all = "camelCase")] 12 pub struct ByteSlice<'a> { 13 pub byte_end: i64, 14 pub byte_start: i64, 15 } 16 + 17 + impl jacquard_common::IntoStatic for ByteSlice<'_> { 18 + type Output = ByteSlice<'static>; 19 + fn into_static(self) -> Self::Output { 20 + ByteSlice { 21 + byte_end: self.byte_end.into_static(), 22 + byte_start: self.byte_start.into_static(), 23 + extra_data: self.extra_data.into_static(), 24 + } 25 + } 26 + } 27 + 28 ///Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. 29 + #[jacquard_derive::lexicon] 30 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 31 #[serde(rename_all = "camelCase")] 32 pub struct Link<'a> { 33 + #[serde(borrow)] 34 pub uri: jacquard_common::types::string::Uri<'a>, 35 } 36 + 37 + impl jacquard_common::IntoStatic for Link<'_> { 38 + type Output = Link<'static>; 39 + fn into_static(self) -> Self::Output { 40 + Link { 41 + uri: self.uri.into_static(), 42 + extra_data: self.extra_data.into_static(), 43 + } 44 + } 45 + } 46 + 47 ///Annotation of a sub-string within rich text. 48 + #[jacquard_derive::lexicon] 49 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 50 #[serde(rename_all = "camelCase")] 51 pub struct Facet<'a> { 52 + #[serde(borrow)] 53 pub features: Vec<jacquard_common::types::value::Data<'a>>, 54 + #[serde(borrow)] 55 + pub index: test_generated::app_bsky::richtext::facet::ByteSlice<'a>, 56 + } 57 + 58 + impl jacquard_common::IntoStatic for Facet<'_> { 59 + type Output = Facet<'static>; 60 + fn into_static(self) -> Self::Output { 61 + Facet { 62 + features: self.features.into_static(), 63 + index: self.index.into_static(), 64 + extra_data: self.extra_data.into_static(), 65 + } 66 + } 67 } 68 + 69 ///Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID. 70 + #[jacquard_derive::lexicon] 71 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 72 #[serde(rename_all = "camelCase")] 73 pub struct Mention<'a> { 74 + #[serde(borrow)] 75 pub did: jacquard_common::types::string::Did<'a>, 76 } 77 + 78 + impl jacquard_common::IntoStatic for Mention<'_> { 79 + type Output = Mention<'static>; 80 + fn into_static(self) -> Self::Output { 81 + Mention { 82 + did: self.did.into_static(), 83 + extra_data: self.extra_data.into_static(), 84 + } 85 + } 86 + } 87 + 88 ///Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). 89 + #[jacquard_derive::lexicon] 90 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 91 #[serde(rename_all = "camelCase")] 92 pub struct Tag<'a> { 93 + #[serde(borrow)] 94 pub tag: jacquard_common::CowStr<'a>, 95 } 96 + 97 + impl jacquard_common::IntoStatic for Tag<'_> { 98 + type Output = Tag<'static>; 99 + fn into_static(self) -> Self::Output { 100 + Tag { 101 + tag: self.tag.into_static(), 102 + extra_data: self.extra_data.into_static(), 103 + } 104 + } 105 + }
+6 -1
crates/jacquard-lexicon/target/test_codegen_output/com_atproto.rs
··· 1 pub mod label; 2 - pub mod repo;
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 pub mod label; 7 + pub mod repo;
+157 -28
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/label.rs
··· 1 ///Metadata tag on an atproto resource (eg, repo or record). 2 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 3 #[serde(rename_all = "camelCase")] 4 pub struct Label<'a> { 5 - #[serde(skip_serializing_if = "Option::is_none")] 6 - pub cid: Option<jacquard_common::types::string::Cid<'a>>, 7 pub cts: jacquard_common::types::string::Datetime, 8 - #[serde(skip_serializing_if = "Option::is_none")] 9 - pub exp: Option<jacquard_common::types::string::Datetime>, 10 - #[serde(skip_serializing_if = "Option::is_none")] 11 - pub neg: Option<bool>, 12 - #[serde(skip_serializing_if = "Option::is_none")] 13 - pub sig: Option<jacquard_common::types::value::Bytes>, 14 pub src: jacquard_common::types::string::Did<'a>, 15 pub uri: jacquard_common::types::string::Uri<'a>, 16 pub val: jacquard_common::CowStr<'a>, 17 - #[serde(skip_serializing_if = "Option::is_none")] 18 - pub ver: Option<i64>, 19 } 20 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 21 pub enum LabelValue<'a> { 22 - #[serde(rename = "!hide")] 23 Hide, 24 - #[serde(rename = "!no-promote")] 25 NoPromote, 26 - #[serde(rename = "!warn")] 27 Warn, 28 - #[serde(rename = "!no-unauthenticated")] 29 NoUnauthenticated, 30 - #[serde(rename = "dmca-violation")] 31 DmcaViolation, 32 - #[serde(rename = "doxxing")] 33 Doxxing, 34 - #[serde(rename = "porn")] 35 Porn, 36 - #[serde(rename = "sexual")] 37 Sexual, 38 - #[serde(rename = "nudity")] 39 Nudity, 40 - #[serde(rename = "nsfl")] 41 Nsfl, 42 - #[serde(rename = "gore")] 43 Gore, 44 - #[serde(untagged)] 45 Other(jacquard_common::CowStr<'a>), 46 } 47 impl<'a> LabelValue<'a> { 48 pub fn as_str(&self) -> &str { 49 match self { ··· 62 } 63 } 64 } 65 impl<'a> From<&'a str> for LabelValue<'a> { 66 fn from(s: &'a str) -> Self { 67 match s { ··· 80 } 81 } 82 } 83 impl<'a> From<String> for LabelValue<'a> { 84 fn from(s: String) -> Self { 85 match s.as_str() { ··· 98 } 99 } 100 } 101 impl<'a> AsRef<str> for LabelValue<'a> { 102 fn as_ref(&self) -> &str { 103 self.as_str() 104 } 105 } 106 impl<'a> serde::Serialize for LabelValue<'a> { 107 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 108 where ··· 111 serializer.serialize_str(self.as_str()) 112 } 113 } 114 impl<'de, 'a> serde::Deserialize<'de> for LabelValue<'a> 115 where 116 'de: 'a, ··· 123 Ok(Self::from(s)) 124 } 125 } 126 ///Declares a label value and its expected interpretations and behaviors. 127 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 128 #[serde(rename_all = "camelCase")] 129 pub struct LabelValueDefinition<'a> { 130 - #[serde(skip_serializing_if = "Option::is_none")] 131 - pub adult_only: Option<bool>, 132 pub blurs: jacquard_common::CowStr<'a>, 133 - #[serde(skip_serializing_if = "Option::is_none")] 134 - pub default_setting: Option<jacquard_common::CowStr<'a>>, 135 pub identifier: jacquard_common::CowStr<'a>, 136 - pub locales: Vec<jacquard_common::types::value::Data<'a>>, 137 pub severity: jacquard_common::CowStr<'a>, 138 } 139 ///Strings which describe the label in the UI, localized into a specific language. 140 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 141 #[serde(rename_all = "camelCase")] 142 pub struct LabelValueDefinitionStrings<'a> { 143 pub description: jacquard_common::CowStr<'a>, 144 pub lang: jacquard_common::types::string::Language, 145 pub name: jacquard_common::CowStr<'a>, 146 } 147 ///Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel. 148 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 149 #[serde(rename_all = "camelCase")] 150 pub struct SelfLabel<'a> { 151 pub val: jacquard_common::CowStr<'a>, 152 } 153 ///Metadata tags on an atproto record, published by the author within the record. 154 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 155 #[serde(rename_all = "camelCase")] 156 pub struct SelfLabels<'a> { 157 - pub values: Vec<jacquard_common::types::value::Data<'a>>, 158 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: com.atproto.label.defs 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 ///Metadata tag on an atproto resource (eg, repo or record). 9 + #[jacquard_derive::lexicon] 10 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 11 #[serde(rename_all = "camelCase")] 12 pub struct Label<'a> { 13 + ///Optionally, CID specifying the specific version of 'uri' resource this label applies to. 14 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 + #[serde(borrow)] 16 + pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>, 17 + ///Timestamp when this label was created. 18 pub cts: jacquard_common::types::string::Datetime, 19 + ///Timestamp at which this label expires (no longer applies). 20 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 + pub exp: std::option::Option<jacquard_common::types::string::Datetime>, 22 + ///If true, this is a negation label, overwriting a previous label. 23 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 24 + pub neg: std::option::Option<bool>, 25 + ///Signature of dag-cbor encoded label. 26 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 27 + pub sig: std::option::Option<bytes::Bytes>, 28 + ///DID of the actor who created this label. 29 + #[serde(borrow)] 30 pub src: jacquard_common::types::string::Did<'a>, 31 + ///AT URI of the record, repository (account), or other resource that this label applies to. 32 + #[serde(borrow)] 33 pub uri: jacquard_common::types::string::Uri<'a>, 34 + ///The short string name of the value or type of this label. 35 + #[serde(borrow)] 36 pub val: jacquard_common::CowStr<'a>, 37 + ///The AT Protocol version of the label object. 38 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 39 + pub ver: std::option::Option<i64>, 40 + } 41 + 42 + impl jacquard_common::IntoStatic for Label<'_> { 43 + type Output = Label<'static>; 44 + fn into_static(self) -> Self::Output { 45 + Label { 46 + cid: self.cid.into_static(), 47 + cts: self.cts.into_static(), 48 + exp: self.exp.into_static(), 49 + neg: self.neg.into_static(), 50 + sig: self.sig.into_static(), 51 + src: self.src.into_static(), 52 + uri: self.uri.into_static(), 53 + val: self.val.into_static(), 54 + ver: self.ver.into_static(), 55 + extra_data: self.extra_data.into_static(), 56 + } 57 + } 58 } 59 + 60 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 61 pub enum LabelValue<'a> { 62 Hide, 63 NoPromote, 64 Warn, 65 NoUnauthenticated, 66 DmcaViolation, 67 Doxxing, 68 Porn, 69 Sexual, 70 Nudity, 71 Nsfl, 72 Gore, 73 Other(jacquard_common::CowStr<'a>), 74 } 75 + 76 impl<'a> LabelValue<'a> { 77 pub fn as_str(&self) -> &str { 78 match self { ··· 91 } 92 } 93 } 94 + 95 impl<'a> From<&'a str> for LabelValue<'a> { 96 fn from(s: &'a str) -> Self { 97 match s { ··· 110 } 111 } 112 } 113 + 114 impl<'a> From<String> for LabelValue<'a> { 115 fn from(s: String) -> Self { 116 match s.as_str() { ··· 129 } 130 } 131 } 132 + 133 impl<'a> AsRef<str> for LabelValue<'a> { 134 fn as_ref(&self) -> &str { 135 self.as_str() 136 } 137 } 138 + 139 impl<'a> serde::Serialize for LabelValue<'a> { 140 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 141 where ··· 144 serializer.serialize_str(self.as_str()) 145 } 146 } 147 + 148 impl<'de, 'a> serde::Deserialize<'de> for LabelValue<'a> 149 where 150 'de: 'a, ··· 157 Ok(Self::from(s)) 158 } 159 } 160 + 161 + impl jacquard_common::IntoStatic for LabelValue<'_> { 162 + type Output = LabelValue<'static>; 163 + fn into_static(self) -> Self::Output { 164 + match self { 165 + LabelValue::Hide => LabelValue::Hide, 166 + LabelValue::NoPromote => LabelValue::NoPromote, 167 + LabelValue::Warn => LabelValue::Warn, 168 + LabelValue::NoUnauthenticated => LabelValue::NoUnauthenticated, 169 + LabelValue::DmcaViolation => LabelValue::DmcaViolation, 170 + LabelValue::Doxxing => LabelValue::Doxxing, 171 + LabelValue::Porn => LabelValue::Porn, 172 + LabelValue::Sexual => LabelValue::Sexual, 173 + LabelValue::Nudity => LabelValue::Nudity, 174 + LabelValue::Nsfl => LabelValue::Nsfl, 175 + LabelValue::Gore => LabelValue::Gore, 176 + LabelValue::Other(v) => LabelValue::Other(v.into_static()), 177 + } 178 + } 179 + } 180 + 181 ///Declares a label value and its expected interpretations and behaviors. 182 + #[jacquard_derive::lexicon] 183 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 184 #[serde(rename_all = "camelCase")] 185 pub struct LabelValueDefinition<'a> { 186 + ///Does the user need to have adult content enabled in order to configure this label? 187 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 188 + pub adult_only: std::option::Option<bool>, 189 + ///What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing. 190 + #[serde(borrow)] 191 pub blurs: jacquard_common::CowStr<'a>, 192 + ///The default setting for this label. 193 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 194 + #[serde(borrow)] 195 + pub default_setting: std::option::Option<jacquard_common::CowStr<'a>>, 196 + ///The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+). 197 + #[serde(borrow)] 198 pub identifier: jacquard_common::CowStr<'a>, 199 + #[serde(borrow)] 200 + pub locales: Vec< 201 + test_generated::com_atproto::label::LabelValueDefinitionStrings<'a>, 202 + >, 203 + ///How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing. 204 + #[serde(borrow)] 205 pub severity: jacquard_common::CowStr<'a>, 206 } 207 + 208 + impl jacquard_common::IntoStatic for LabelValueDefinition<'_> { 209 + type Output = LabelValueDefinition<'static>; 210 + fn into_static(self) -> Self::Output { 211 + LabelValueDefinition { 212 + adult_only: self.adult_only.into_static(), 213 + blurs: self.blurs.into_static(), 214 + default_setting: self.default_setting.into_static(), 215 + identifier: self.identifier.into_static(), 216 + locales: self.locales.into_static(), 217 + severity: self.severity.into_static(), 218 + extra_data: self.extra_data.into_static(), 219 + } 220 + } 221 + } 222 + 223 ///Strings which describe the label in the UI, localized into a specific language. 224 + #[jacquard_derive::lexicon] 225 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 226 #[serde(rename_all = "camelCase")] 227 pub struct LabelValueDefinitionStrings<'a> { 228 + ///A longer description of what the label means and why it might be applied. 229 + #[serde(borrow)] 230 pub description: jacquard_common::CowStr<'a>, 231 + ///The code of the language these strings are written in. 232 pub lang: jacquard_common::types::string::Language, 233 + ///A short human-readable name for the label. 234 + #[serde(borrow)] 235 pub name: jacquard_common::CowStr<'a>, 236 } 237 + 238 + impl jacquard_common::IntoStatic for LabelValueDefinitionStrings<'_> { 239 + type Output = LabelValueDefinitionStrings<'static>; 240 + fn into_static(self) -> Self::Output { 241 + LabelValueDefinitionStrings { 242 + description: self.description.into_static(), 243 + lang: self.lang.into_static(), 244 + name: self.name.into_static(), 245 + extra_data: self.extra_data.into_static(), 246 + } 247 + } 248 + } 249 + 250 ///Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel. 251 + #[jacquard_derive::lexicon] 252 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 253 #[serde(rename_all = "camelCase")] 254 pub struct SelfLabel<'a> { 255 + ///The short string name of the value or type of this label. 256 + #[serde(borrow)] 257 pub val: jacquard_common::CowStr<'a>, 258 } 259 + 260 + impl jacquard_common::IntoStatic for SelfLabel<'_> { 261 + type Output = SelfLabel<'static>; 262 + fn into_static(self) -> Self::Output { 263 + SelfLabel { 264 + val: self.val.into_static(), 265 + extra_data: self.extra_data.into_static(), 266 + } 267 + } 268 + } 269 + 270 ///Metadata tags on an atproto record, published by the author within the record. 271 + #[jacquard_derive::lexicon] 272 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 273 #[serde(rename_all = "camelCase")] 274 pub struct SelfLabels<'a> { 275 + #[serde(borrow)] 276 + pub values: Vec<test_generated::com_atproto::label::SelfLabel<'a>>, 277 } 278 + 279 + impl jacquard_common::IntoStatic for SelfLabels<'_> { 280 + type Output = SelfLabels<'static>; 281 + fn into_static(self) -> Self::Output { 282 + SelfLabels { 283 + values: self.values.into_static(), 284 + extra_data: self.extra_data.into_static(), 285 + } 286 + } 287 + }
+6 -1
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/repo.rs
··· 1 - pub mod strong_ref;
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod strong_ref;
+21
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/repo/strong_ref.rs
··· 1 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 2 #[serde(rename_all = "camelCase")] 3 pub struct StrongRef<'a> { 4 pub cid: jacquard_common::types::string::Cid<'a>, 5 pub uri: jacquard_common::types::string::AtUri<'a>, 6 }
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: com.atproto.repo.strongRef 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] 10 #[serde(rename_all = "camelCase")] 11 pub struct StrongRef<'a> { 12 + #[serde(borrow)] 13 pub cid: jacquard_common::types::string::Cid<'a>, 14 + #[serde(borrow)] 15 pub uri: jacquard_common::types::string::AtUri<'a>, 16 } 17 + 18 + impl jacquard_common::IntoStatic for StrongRef<'_> { 19 + type Output = StrongRef<'static>; 20 + fn into_static(self) -> Self::Output { 21 + StrongRef { 22 + cid: self.cid.into_static(), 23 + uri: self.uri.into_static(), 24 + extra_data: self.extra_data.into_static(), 25 + } 26 + } 27 + }
+6 -1
crates/jacquard-lexicon/target/test_codegen_output/lib.rs
··· 1 pub mod app_bsky; 2 - pub mod com_atproto;
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 pub mod app_bsky; 7 + pub mod com_atproto;
+149 -25
crates/jacquard/src/client.rs
··· 4 use std::fmt::Display; 5 use std::future::Future; 6 7 - pub use error::{ClientError, Result}; 8 use bytes::Bytes; 9 use http::{ 10 HeaderName, HeaderValue, Request, 11 header::{AUTHORIZATION, CONTENT_TYPE, InvalidHeaderValue}, 12 }; 13 pub use response::Response; 14 - use serde::Serialize; 15 16 - use jacquard_common::{CowStr, types::xrpc::{XrpcMethod, XrpcRequest}}; 17 18 pub trait HttpClient { 19 type Error: std::error::Error + Display + Send + Sync + 'static; ··· 98 99 // Add query parameters for Query methods 100 if let XrpcMethod::Query = R::METHOD { 101 - if let Ok(qs) = serde_html_form::to_string(&request) { 102 - if !qs.is_empty() { 103 - uri.push('?'); 104 - uri.push_str(&qs); 105 - } 106 } 107 } 108 ··· 139 } 140 141 // Serialize body for procedures 142 - let body = if let XrpcMethod::Procedure(encoding) = R::METHOD { 143 - if encoding == "application/json" { 144 - serde_json::to_vec(&request).map_err(error::EncodeError::Json)? 145 - } else { 146 - // For other encodings, we'd need different serialization 147 - vec![] 148 - } 149 } else { 150 vec![] 151 }; 152 153 let http_request = builder.body(body).expect("Failed to build HTTP request"); 154 155 // Send HTTP request 156 - let http_response = client.send_http(http_request).await.map_err(|e| { 157 - error::TransportError::Other(Box::new(e)) 158 - })?; 159 160 - // Check status 161 - if !http_response.status().is_success() { 162 return Err(ClientError::Http(error::HttpError { 163 - status: http_response.status(), 164 - body: Some(Bytes::from(http_response.body().clone())), 165 })); 166 } 167 168 - // Convert to Response 169 - let buffer = Bytes::from(http_response.into_body()); 170 - Ok(Response::new(buffer)) 171 }
··· 4 use std::fmt::Display; 5 use std::future::Future; 6 7 use bytes::Bytes; 8 + pub use error::{ClientError, Result}; 9 use http::{ 10 HeaderName, HeaderValue, Request, 11 header::{AUTHORIZATION, CONTENT_TYPE, InvalidHeaderValue}, 12 }; 13 pub use response::Response; 14 + 15 + use jacquard_common::{ 16 + CowStr, IntoStatic, 17 + types::{ 18 + string::{Did, Handle}, 19 + xrpc::{XrpcMethod, XrpcRequest}, 20 + }, 21 + }; 22 + 23 + /// Implement HttpClient for reqwest::Client 24 + impl HttpClient for reqwest::Client { 25 + type Error = reqwest::Error; 26 + 27 + async fn send_http( 28 + &self, 29 + request: Request<Vec<u8>>, 30 + ) -> core::result::Result<http::Response<Vec<u8>>, Self::Error> { 31 + // Convert http::Request to reqwest::Request 32 + let (parts, body) = request.into_parts(); 33 34 + let mut req = self.request(parts.method, parts.uri.to_string()).body(body); 35 + 36 + // Copy headers 37 + for (name, value) in parts.headers.iter() { 38 + req = req.header(name.as_str(), value.as_bytes()); 39 + } 40 + 41 + // Send request 42 + let resp = req.send().await?; 43 + 44 + // Convert reqwest::Response to http::Response 45 + let mut builder = http::Response::builder().status(resp.status()); 46 + 47 + // Copy headers 48 + for (name, value) in resp.headers().iter() { 49 + builder = builder.header(name.as_str(), value.as_bytes()); 50 + } 51 + 52 + // Read body 53 + let body = resp.bytes().await?.to_vec(); 54 + 55 + Ok(builder.body(body).expect("Failed to build response")) 56 + } 57 + } 58 59 pub trait HttpClient { 60 type Error: std::error::Error + Display + Send + Sync + 'static; ··· 139 140 // Add query parameters for Query methods 141 if let XrpcMethod::Query = R::METHOD { 142 + let qs = serde_html_form::to_string(&request).map_err(error::EncodeError::from)?; 143 + if !qs.is_empty() { 144 + uri.push('?'); 145 + uri.push_str(&qs); 146 } 147 } 148 ··· 179 } 180 181 // Serialize body for procedures 182 + let body = if let XrpcMethod::Procedure(_) = R::METHOD { 183 + request.encode_body()? 184 } else { 185 vec![] 186 }; 187 188 + // TODO: make this not panic 189 let http_request = builder.body(body).expect("Failed to build HTTP request"); 190 191 // Send HTTP request 192 + let http_response = client 193 + .send_http(http_request) 194 + .await 195 + .map_err(|e| error::TransportError::Other(Box::new(e)))?; 196 + 197 + let status = http_response.status(); 198 + let buffer = Bytes::from(http_response.into_body()); 199 200 + // XRPC errors come as 400/401 with structured error bodies 201 + // Other error status codes (404, 500, etc.) are generic HTTP errors 202 + if !status.is_success() && !matches!(status.as_u16(), 400 | 401) { 203 return Err(ClientError::Http(error::HttpError { 204 + status, 205 + body: Some(buffer), 206 })); 207 } 208 209 + // Response will parse XRPC errors for 400/401, or output for 2xx 210 + Ok(Response::new(buffer, status)) 211 + } 212 + 213 + /// Session information from createSession 214 + #[derive(Debug, Clone)] 215 + pub struct Session { 216 + pub access_jwt: CowStr<'static>, 217 + pub refresh_jwt: CowStr<'static>, 218 + pub did: Did<'static>, 219 + pub handle: Handle<'static>, 220 + } 221 + 222 + impl From<jacquard_api::com_atproto::server::create_session::CreateSessionOutput<'_>> for Session { 223 + fn from( 224 + output: jacquard_api::com_atproto::server::create_session::CreateSessionOutput<'_>, 225 + ) -> Self { 226 + Self { 227 + access_jwt: output.access_jwt.into_static(), 228 + refresh_jwt: output.refresh_jwt.into_static(), 229 + did: output.did.into_static(), 230 + handle: output.handle.into_static(), 231 + } 232 + } 233 + } 234 + 235 + /// Authenticated XRPC client that includes session tokens 236 + pub struct AuthenticatedClient<C> { 237 + client: C, 238 + base_uri: CowStr<'static>, 239 + session: Option<Session>, 240 + } 241 + 242 + impl<C> AuthenticatedClient<C> { 243 + /// Create a new authenticated client with a base URI 244 + pub fn new(client: C, base_uri: CowStr<'static>) -> Self { 245 + Self { 246 + client, 247 + base_uri: base_uri, 248 + session: None, 249 + } 250 + } 251 + 252 + /// Set the session 253 + pub fn set_session(&mut self, session: Session) { 254 + self.session = Some(session); 255 + } 256 + 257 + /// Get the current session 258 + pub fn session(&self) -> Option<&Session> { 259 + self.session.as_ref() 260 + } 261 + 262 + /// Clear the session 263 + pub fn clear_session(&mut self) { 264 + self.session = None; 265 + } 266 + } 267 + 268 + impl<C: HttpClient> HttpClient for AuthenticatedClient<C> { 269 + type Error = C::Error; 270 + 271 + fn send_http( 272 + &self, 273 + request: Request<Vec<u8>>, 274 + ) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, Self::Error>> { 275 + self.client.send_http(request) 276 + } 277 + } 278 + 279 + impl<C: HttpClient> XrpcClient for AuthenticatedClient<C> { 280 + fn base_uri(&self) -> CowStr<'_> { 281 + self.base_uri.clone() 282 + } 283 + 284 + async fn authorization_token(&self, is_refresh: bool) -> Option<AuthorizationToken<'_>> { 285 + if is_refresh { 286 + self.session 287 + .as_ref() 288 + .map(|s| AuthorizationToken::Bearer(s.refresh_jwt.clone())) 289 + } else { 290 + self.session 291 + .as_ref() 292 + .map(|s| AuthorizationToken::Bearer(s.access_jwt.clone())) 293 + } 294 + } 295 }
+2 -15
crates/jacquard/src/client/error.rs
··· 59 Other(Box<dyn std::error::Error + Send + Sync>), 60 } 61 62 - #[derive(Debug, thiserror::Error, miette::Diagnostic)] 63 - pub enum EncodeError { 64 - #[error("Failed to serialize query: {0}")] 65 - Query( 66 - #[from] 67 - #[source] 68 - serde_html_form::ser::Error, 69 - ), 70 - #[error("Failed to serialize JSON: {0}")] 71 - Json( 72 - #[from] 73 - #[source] 74 - serde_json::Error, 75 - ), 76 - } 77 78 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 79 pub enum DecodeError {
··· 59 Other(Box<dyn std::error::Error + Send + Sync>), 60 } 61 62 + // Re-export EncodeError from common 63 + pub use jacquard_common::types::xrpc::EncodeError; 64 65 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 66 pub enum DecodeError {
+109 -12
crates/jacquard/src/client/response.rs
··· 1 use bytes::Bytes; 2 use jacquard_common::IntoStatic; 3 use jacquard_common::types::xrpc::XrpcRequest; 4 use std::marker::PhantomData; 5 6 /// XRPC response wrapper that owns the response buffer 7 /// 8 /// Allows borrowing from the buffer when parsing to avoid unnecessary allocations. 9 pub struct Response<R: XrpcRequest> { 10 buffer: Bytes, 11 _marker: PhantomData<R>, 12 } 13 14 impl<R: XrpcRequest> Response<R> { 15 - /// Create a new response from a buffer 16 - pub fn new(buffer: Bytes) -> Self { 17 Self { 18 buffer, 19 _marker: PhantomData, 20 } 21 } 22 23 /// Parse the response, borrowing from the internal buffer ··· 35 serde_json::from_slice(buffer) 36 } 37 38 - let output = parse_output::<R>(&self.buffer); 39 - if let Ok(output) = output { 40 - Ok(output) 41 - } else { 42 - // Try to parse as error 43 match parse_error::<R>(&self.buffer) { 44 Ok(error) => Err(XrpcError::Xrpc(error)), 45 Err(e) => Err(XrpcError::Decode(e)), 46 } 47 } ··· 66 serde_json::from_slice(buffer) 67 } 68 69 - let output = parse_output::<R>(&self.buffer); 70 - if let Ok(output) = output { 71 - Ok(output.into_static()) 72 - } else { 73 - // Try to parse as error 74 match parse_error::<R>(&self.buffer) { 75 Ok(error) => Err(XrpcError::Xrpc(error.into_static())), 76 Err(e) => Err(XrpcError::Decode(e)), 77 } 78 } ··· 84 } 85 } 86 87 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 88 pub enum XrpcError<E: std::error::Error + IntoStatic> { 89 #[error("XRPC error: {0}")] 90 Xrpc(E), 91 #[error("Failed to decode response: {0}")] 92 Decode(#[from] serde_json::Error), 93 }
··· 1 use bytes::Bytes; 2 + use http::StatusCode; 3 use jacquard_common::IntoStatic; 4 use jacquard_common::types::xrpc::XrpcRequest; 5 + use serde::Deserialize; 6 use std::marker::PhantomData; 7 + 8 + use super::error::AuthError; 9 10 /// XRPC response wrapper that owns the response buffer 11 /// 12 /// Allows borrowing from the buffer when parsing to avoid unnecessary allocations. 13 pub struct Response<R: XrpcRequest> { 14 buffer: Bytes, 15 + status: StatusCode, 16 _marker: PhantomData<R>, 17 } 18 19 impl<R: XrpcRequest> Response<R> { 20 + /// Create a new response from a buffer and status code 21 + pub fn new(buffer: Bytes, status: StatusCode) -> Self { 22 Self { 23 buffer, 24 + status, 25 _marker: PhantomData, 26 } 27 + } 28 + 29 + /// Get the HTTP status code 30 + pub fn status(&self) -> StatusCode { 31 + self.status 32 } 33 34 /// Parse the response, borrowing from the internal buffer ··· 46 serde_json::from_slice(buffer) 47 } 48 49 + // 200: parse as output 50 + if self.status.is_success() { 51 + match parse_output::<R>(&self.buffer) { 52 + Ok(output) => Ok(output), 53 + Err(e) => Err(XrpcError::Decode(e)), 54 + } 55 + // 400: try typed XRPC error, fallback to generic error 56 + } else if self.status.as_u16() == 400 { 57 match parse_error::<R>(&self.buffer) { 58 Ok(error) => Err(XrpcError::Xrpc(error)), 59 + Err(_) => { 60 + // Fallback to generic error (InvalidRequest, ExpiredToken, etc.) 61 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 62 + Ok(generic) => { 63 + // Map auth-related errors to AuthError 64 + match generic.error.as_str() { 65 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 66 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 67 + _ => Err(XrpcError::Generic(generic)), 68 + } 69 + } 70 + Err(e) => Err(XrpcError::Decode(e)), 71 + } 72 + } 73 + } 74 + // 401: always auth error 75 + } else { 76 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 77 + Ok(generic) => { 78 + match generic.error.as_str() { 79 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 80 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 81 + _ => Err(XrpcError::Auth(AuthError::NotAuthenticated)), 82 + } 83 + } 84 Err(e) => Err(XrpcError::Decode(e)), 85 } 86 } ··· 105 serde_json::from_slice(buffer) 106 } 107 108 + // 200: parse as output 109 + if self.status.is_success() { 110 + match parse_output::<R>(&self.buffer) { 111 + Ok(output) => Ok(output.into_static()), 112 + Err(e) => Err(XrpcError::Decode(e)), 113 + } 114 + // 400: try typed XRPC error, fallback to generic error 115 + } else if self.status.as_u16() == 400 { 116 match parse_error::<R>(&self.buffer) { 117 Ok(error) => Err(XrpcError::Xrpc(error.into_static())), 118 + Err(_) => { 119 + // Fallback to generic error (InvalidRequest, ExpiredToken, etc.) 120 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 121 + Ok(generic) => { 122 + // Map auth-related errors to AuthError 123 + match generic.error.as_str() { 124 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 125 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 126 + _ => Err(XrpcError::Generic(generic)), 127 + } 128 + } 129 + Err(e) => Err(XrpcError::Decode(e)), 130 + } 131 + } 132 + } 133 + // 401: always auth error 134 + } else { 135 + match serde_json::from_slice::<GenericXrpcError>(&self.buffer) { 136 + Ok(generic) => { 137 + match generic.error.as_str() { 138 + "ExpiredToken" => Err(XrpcError::Auth(AuthError::TokenExpired)), 139 + "InvalidToken" => Err(XrpcError::Auth(AuthError::InvalidToken)), 140 + _ => Err(XrpcError::Auth(AuthError::NotAuthenticated)), 141 + } 142 + } 143 Err(e) => Err(XrpcError::Decode(e)), 144 } 145 } ··· 151 } 152 } 153 154 + /// Generic XRPC error format (for InvalidRequest, etc.) 155 + #[derive(Debug, Clone, Deserialize)] 156 + pub struct GenericXrpcError { 157 + pub error: String, 158 + pub message: Option<String>, 159 + } 160 + 161 + impl std::fmt::Display for GenericXrpcError { 162 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 163 + if let Some(msg) = &self.message { 164 + write!(f, "{}: {}", self.error, msg) 165 + } else { 166 + write!(f, "{}", self.error) 167 + } 168 + } 169 + } 170 + 171 + impl std::error::Error for GenericXrpcError {} 172 + 173 #[derive(Debug, thiserror::Error, miette::Diagnostic)] 174 pub enum XrpcError<E: std::error::Error + IntoStatic> { 175 + /// Typed XRPC error from the endpoint's error enum 176 #[error("XRPC error: {0}")] 177 Xrpc(E), 178 + 179 + /// Authentication error (ExpiredToken, InvalidToken, etc.) 180 + #[error("Authentication error: {0}")] 181 + Auth(#[from] AuthError), 182 + 183 + /// Generic XRPC error (InvalidRequest, etc.) 184 + #[error("XRPC error: {0}")] 185 + Generic(GenericXrpcError), 186 + 187 + /// Failed to decode response 188 #[error("Failed to decode response: {0}")] 189 Decode(#[from] serde_json::Error), 190 }