+2
-3
crates/jacquard-api/src/app_bsky/feed/get_suggested_feeds.rs
+2
-3
crates/jacquard-api/src/app_bsky/feed/get_suggested_feeds.rs
···
50
50
51
51
impl jacquard_common::types::xrpc::XrpcRequest for GetSuggestedFeeds<'_> {
52
52
const NSID: &'static str = "app.bsky.feed.getSuggestedFeeds";
53
-
const METHOD: jacquard_common::types::xrpc::XrpcMethod =
54
-
jacquard_common::types::xrpc::XrpcMethod::Query;
53
+
const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Query;
55
54
const OUTPUT_ENCODING: &'static str = "application/json";
56
55
type Output<'de> = GetSuggestedFeedsOutput<'de>;
57
56
type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>;
58
-
}
57
+
}
+2
-3
crates/jacquard-api/src/app_bsky/unspecced/get_onboarding_suggested_starter_packs.rs
+2
-3
crates/jacquard-api/src/app_bsky/unspecced/get_onboarding_suggested_starter_packs.rs
···
40
40
41
41
impl jacquard_common::types::xrpc::XrpcRequest for GetOnboardingSuggestedStarterPacks {
42
42
const NSID: &'static str = "app.bsky.unspecced.getOnboardingSuggestedStarterPacks";
43
-
const METHOD: jacquard_common::types::xrpc::XrpcMethod =
44
-
jacquard_common::types::xrpc::XrpcMethod::Query;
43
+
const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Query;
45
44
const OUTPUT_ENCODING: &'static str = "application/json";
46
45
type Output<'de> = GetOnboardingSuggestedStarterPacksOutput<'de>;
47
46
type Err<'de> = jacquard_common::types::xrpc::GenericError<'de>;
48
-
}
47
+
}
+11
-8
crates/jacquard-api/src/app_bsky/video/upload_video.rs
+11
-8
crates/jacquard-api/src/app_bsky/video/upload_video.rs
···
5
5
// This file was automatically generated from Lexicon schemas.
6
6
// Any manual changes will be overwritten on the next regeneration.
7
7
8
-
#[jacquard_derive::lexicon]
9
8
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
10
9
#[serde(rename_all = "camelCase")]
11
-
pub struct UploadVideo<'a> {}
12
-
impl jacquard_common::IntoStatic for UploadVideo<'_> {
13
-
type Output = UploadVideo<'static>;
10
+
pub struct UploadVideo {
11
+
pub body: bytes::Bytes,
12
+
}
13
+
14
+
impl jacquard_common::IntoStatic for UploadVideo {
15
+
type Output = UploadVideo;
14
16
fn into_static(self) -> Self::Output {
15
-
UploadVideo {
16
-
extra_data: self.extra_data.into_static(),
17
-
}
17
+
self
18
18
}
19
19
}
20
20
···
36
36
}
37
37
}
38
38
39
-
impl jacquard_common::types::xrpc::XrpcRequest for UploadVideo<'_> {
39
+
impl jacquard_common::types::xrpc::XrpcRequest for UploadVideo {
40
40
const NSID: &'static str = "app.bsky.video.uploadVideo";
41
41
const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure(
42
42
"video/mp4",
···
44
44
const OUTPUT_ENCODING: &'static str = "application/json";
45
45
type Output<'de> = UploadVideoOutput<'de>;
46
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
+
}
47
50
}
+11
-8
crates/jacquard-api/src/com_atproto/repo/import_repo.rs
+11
-8
crates/jacquard-api/src/com_atproto/repo/import_repo.rs
···
5
5
// This file was automatically generated from Lexicon schemas.
6
6
// Any manual changes will be overwritten on the next regeneration.
7
7
8
-
#[jacquard_derive::lexicon]
9
8
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
10
9
#[serde(rename_all = "camelCase")]
11
-
pub struct ImportRepo<'a> {}
12
-
impl jacquard_common::IntoStatic for ImportRepo<'_> {
13
-
type Output = ImportRepo<'static>;
10
+
pub struct ImportRepo {
11
+
pub body: bytes::Bytes,
12
+
}
13
+
14
+
impl jacquard_common::IntoStatic for ImportRepo {
15
+
type Output = ImportRepo;
14
16
fn into_static(self) -> Self::Output {
15
-
ImportRepo {
16
-
extra_data: self.extra_data.into_static(),
17
-
}
17
+
self
18
18
}
19
19
}
20
20
21
-
impl jacquard_common::types::xrpc::XrpcRequest for ImportRepo<'_> {
21
+
impl jacquard_common::types::xrpc::XrpcRequest for ImportRepo {
22
22
const NSID: &'static str = "com.atproto.repo.importRepo";
23
23
const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure(
24
24
"application/vnd.ipld.car",
···
26
26
const OUTPUT_ENCODING: &'static str = "application/json";
27
27
type Output<'de> = ();
28
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
+
}
29
32
}
+11
-8
crates/jacquard-api/src/com_atproto/repo/upload_blob.rs
+11
-8
crates/jacquard-api/src/com_atproto/repo/upload_blob.rs
···
5
5
// This file was automatically generated from Lexicon schemas.
6
6
// Any manual changes will be overwritten on the next regeneration.
7
7
8
-
#[jacquard_derive::lexicon]
9
8
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
10
9
#[serde(rename_all = "camelCase")]
11
-
pub struct UploadBlob<'a> {}
12
-
impl jacquard_common::IntoStatic for UploadBlob<'_> {
13
-
type Output = UploadBlob<'static>;
10
+
pub struct UploadBlob {
11
+
pub body: bytes::Bytes,
12
+
}
13
+
14
+
impl jacquard_common::IntoStatic for UploadBlob {
15
+
type Output = UploadBlob;
14
16
fn into_static(self) -> Self::Output {
15
-
UploadBlob {
16
-
extra_data: self.extra_data.into_static(),
17
-
}
17
+
self
18
18
}
19
19
}
20
20
···
36
36
}
37
37
}
38
38
39
-
impl jacquard_common::types::xrpc::XrpcRequest for UploadBlob<'_> {
39
+
impl jacquard_common::types::xrpc::XrpcRequest for UploadBlob {
40
40
const NSID: &'static str = "com.atproto.repo.uploadBlob";
41
41
const METHOD: jacquard_common::types::xrpc::XrpcMethod = jacquard_common::types::xrpc::XrpcMethod::Procedure(
42
42
"*/*",
···
44
44
const OUTPUT_ENCODING: &'static str = "application/json";
45
45
type Output<'de> = UploadBlobOutput<'de>;
46
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
+
}
47
50
}
+29
-1
crates/jacquard-common/src/types/xrpc.rs
+29
-1
crates/jacquard-common/src/types/xrpc.rs
···
1
-
use serde::de::DeserializeOwned;
2
1
use serde::{Deserialize, Serialize};
3
2
use std::error::Error;
4
3
use std::fmt::{self, Debug};
5
4
6
5
use crate::IntoStatic;
7
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
+
}
8
29
9
30
/// XRPC method type
10
31
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
···
53
74
54
75
/// Error type for this request
55
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
+
}
56
84
}
57
85
58
86
/// Error type for XRPC endpoints that don't define any errors
+79
-26
crates/jacquard-lexicon/src/codegen.rs
+79
-26
crates/jacquard-lexicon/src/codegen.rs
···
662
662
params_has_lifetime,
663
663
has_output,
664
664
has_errors,
665
+
false, // queries never have binary inputs
665
666
)?;
666
667
output.push(xrpc_impl);
667
668
···
680
681
let type_base = self.def_to_type_name(nsid, def_name);
681
682
let mut output = Vec::new();
682
683
683
-
// Input bodies always have lifetimes (they get #[lexicon] attribute)
684
-
let params_has_lifetime = proc.input.is_some();
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;
685
694
let has_input = proc.input.is_some();
686
695
let has_output = proc.output.is_some();
687
696
let has_errors = proc.errors.is_some();
···
726
735
params_has_lifetime,
727
736
has_output,
728
737
has_errors,
738
+
is_binary_input,
729
739
)?;
730
740
output.push(xrpc_impl);
731
741
···
1424
1434
) -> Result<TokenStream> {
1425
1435
let ident = syn::Ident::new(type_base, proc_macro2::Span::call_site());
1426
1436
1437
+
// Check if this is a binary body (no schema, just raw bytes)
1438
+
let is_binary_body = body.schema.is_none();
1439
+
1427
1440
let fields = if let Some(schema) = &body.schema {
1428
1441
self.generate_body_fields("", type_base, schema)?
1429
1442
} else {
1430
-
quote! {}
1443
+
// Binary body: just a bytes field
1444
+
quote! {
1445
+
pub body: bytes::Bytes,
1446
+
}
1431
1447
};
1432
1448
1433
1449
let doc = self.generate_doc_comment(body.description.as_ref());
1434
1450
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
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
+
}
1444
1472
}
1445
1473
};
1446
1474
···
1458
1486
}
1459
1487
1460
1488
// 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![]
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
+
}
1472
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)
1473
1514
};
1474
-
let into_static_impl =
1475
-
self.generate_into_static_for_struct(type_base, &field_names, true, true);
1476
1515
1477
1516
Ok(quote! {
1478
1517
#struct_def
···
1923
1962
params_has_lifetime: bool,
1924
1963
has_output: bool,
1925
1964
has_errors: bool,
1965
+
is_binary_input: bool,
1926
1966
) -> Result<TokenStream> {
1927
1967
let output_type = if has_output {
1928
1968
let output_ident = syn::Ident::new(
···
1944
1984
quote! { jacquard_common::types::xrpc::GenericError<'de> }
1945
1985
};
1946
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
+
1947
1998
if has_params {
1948
1999
// Implement on the params/input struct itself
1949
2000
let request_ident = syn::Ident::new(type_base, proc_macro2::Span::call_site());
···
1961
2012
1962
2013
type Output<'de> = #output_type;
1963
2014
type Err<'de> = #error_type;
2015
+
2016
+
#encode_body_method
1964
2017
}
1965
2018
})
1966
2019
} else {
···
2311
2364
println!("\n{}\n", formatted);
2312
2365
2313
2366
// Check structure
2314
-
assert!(formatted.contains("struct GetAuthorFeedParams"));
2367
+
assert!(formatted.contains("struct GetAuthorFeed"));
2315
2368
assert!(formatted.contains("struct GetAuthorFeedOutput"));
2316
2369
assert!(formatted.contains("enum GetAuthorFeedError"));
2317
2370
assert!(formatted.contains("pub actor"));
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky.rs
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky.rs
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed.rs
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed.rs
···
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
+
1
6
pub mod external;
2
7
pub mod images;
3
8
pub mod record;
4
9
pub mod record_with_media;
5
-
pub mod video;
10
+
pub mod video;
+77
-7
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/external.rs
+77
-7
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/external.rs
···
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]
1
9
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
2
10
#[serde(rename_all = "camelCase")]
3
11
pub struct External<'a> {
12
+
#[serde(borrow)]
4
13
pub description: jacquard_common::CowStr<'a>,
5
-
#[serde(skip_serializing_if = "Option::is_none")]
6
-
pub thumb: Option<jacquard_common::types::blob::Blob<'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)]
7
18
pub title: jacquard_common::CowStr<'a>,
19
+
#[serde(borrow)]
8
20
pub uri: jacquard_common::types::string::Uri<'a>,
9
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
+
10
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]
11
38
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
12
39
#[serde(rename_all = "camelCase")]
13
-
pub struct External<'a> {
14
-
pub external: jacquard_common::types::value::Data<'a>,
40
+
pub struct ExternalRecord<'a> {
41
+
#[serde(borrow)]
42
+
pub external: test_generated::app_bsky::embed::external::External<'a>,
15
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]
16
56
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
17
57
#[serde(rename_all = "camelCase")]
18
58
pub struct View<'a> {
19
-
pub external: jacquard_common::types::value::Data<'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
+
}
20
71
}
72
+
73
+
#[jacquard_derive::lexicon]
21
74
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
22
75
#[serde(rename_all = "camelCase")]
23
76
pub struct ViewExternal<'a> {
77
+
#[serde(borrow)]
24
78
pub description: jacquard_common::CowStr<'a>,
25
-
#[serde(skip_serializing_if = "Option::is_none")]
26
-
pub thumb: Option<jacquard_common::types::string::Uri<'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)]
27
83
pub title: jacquard_common::CowStr<'a>,
84
+
#[serde(borrow)]
28
85
pub uri: jacquard_common::types::string::Uri<'a>,
29
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
+78
-6
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/images.rs
···
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]
1
9
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
2
10
#[serde(rename_all = "camelCase")]
3
11
pub struct Image<'a> {
12
+
///Alt text description of the image, for accessibility.
13
+
#[serde(borrow)]
4
14
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>>,
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)]
7
19
pub image: jacquard_common::types::blob::Blob<'a>,
8
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]
9
35
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
10
36
#[serde(rename_all = "camelCase")]
11
37
pub struct Images<'a> {
12
-
pub images: Vec<jacquard_common::types::value::Data<'a>>,
38
+
#[serde(borrow)]
39
+
pub images: Vec<test_generated::app_bsky::embed::images::Image<'a>>,
13
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]
14
53
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
15
54
#[serde(rename_all = "camelCase")]
16
55
pub struct View<'a> {
17
-
pub images: Vec<jacquard_common::types::value::Data<'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
+
}
18
68
}
69
+
70
+
#[jacquard_derive::lexicon]
19
71
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
20
72
#[serde(rename_all = "camelCase")]
21
73
pub struct ViewImage<'a> {
74
+
///Alt text description of the image, for accessibility.
75
+
#[serde(borrow)]
22
76
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>>,
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)]
25
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)]
26
85
pub thumb: jacquard_common::types::string::Uri<'a>,
27
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
+133
-14
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/record.rs
···
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]
1
9
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
2
10
#[serde(rename_all = "camelCase")]
3
11
pub struct Record<'a> {
4
-
pub record: test_generated::com_atproto::repo::StrongRef<'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
+
}
5
24
}
25
+
26
+
#[jacquard_derive::lexicon]
6
27
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
7
28
#[serde(rename_all = "camelCase")]
8
29
pub struct View<'a> {
9
-
pub record: RecordRecord<'a>,
30
+
#[serde(borrow)]
31
+
pub record: ViewRecordRecord<'a>,
10
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]
11
59
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
12
60
#[serde(rename_all = "camelCase")]
13
61
pub struct ViewBlocked<'a> {
62
+
#[serde(borrow)]
14
63
pub author: jacquard_common::types::value::Data<'a>,
15
64
pub blocked: bool,
65
+
#[serde(borrow)]
16
66
pub uri: jacquard_common::types::string::AtUri<'a>,
17
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]
18
82
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
19
83
#[serde(rename_all = "camelCase")]
20
84
pub struct ViewDetached<'a> {
21
85
pub detached: bool,
86
+
#[serde(borrow)]
22
87
pub uri: jacquard_common::types::string::AtUri<'a>,
23
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]
24
102
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
25
103
#[serde(rename_all = "camelCase")]
26
104
pub struct ViewNotFound<'a> {
27
105
pub not_found: bool,
106
+
#[serde(borrow)]
28
107
pub uri: jacquard_common::types::string::AtUri<'a>,
29
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]
30
122
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
31
123
#[serde(rename_all = "camelCase")]
32
124
pub struct ViewRecord<'a> {
125
+
#[serde(borrow)]
33
126
pub author: jacquard_common::types::value::Data<'a>,
127
+
#[serde(borrow)]
34
128
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>>>,
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>>>,
37
132
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>,
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)]
48
145
pub uri: jacquard_common::types::string::AtUri<'a>,
146
+
///The record data itself.
147
+
#[serde(borrow)]
49
148
pub value: jacquard_common::types::value::Data<'a>,
50
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
+102
-4
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/record_with_media.rs
···
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]
1
9
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
2
10
#[serde(rename_all = "camelCase")]
3
11
pub struct RecordWithMedia<'a> {
4
-
pub media: RecordMedia<'a>,
5
-
pub record: test_generated::app_bsky::embed::Record<'a>,
12
+
#[serde(borrow)]
13
+
pub media: RecordWithMediaRecordMedia<'a>,
14
+
#[serde(borrow)]
15
+
pub record: test_generated::app_bsky::embed::record::Record<'a>,
6
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]
7
63
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
8
64
#[serde(rename_all = "camelCase")]
9
65
pub struct View<'a> {
10
-
pub media: RecordMedia<'a>,
11
-
pub record: test_generated::app_bsky::embed::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
+
}
12
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
+76
-12
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/embed/video.rs
···
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]
1
9
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
2
10
#[serde(rename_all = "camelCase")]
3
11
pub struct Caption<'a> {
12
+
#[serde(borrow)]
4
13
pub file: jacquard_common::types::blob::Blob<'a>,
5
14
pub lang: jacquard_common::types::string::Language,
6
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]
7
29
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
8
30
#[serde(rename_all = "camelCase")]
9
31
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>>>,
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)]
16
46
pub video: jacquard_common::types::blob::Blob<'a>,
17
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]
18
63
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
19
64
#[serde(rename_all = "camelCase")]
20
65
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>>,
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)]
25
73
pub cid: jacquard_common::types::string::Cid<'a>,
74
+
#[serde(borrow)]
26
75
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>>,
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>>,
29
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
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed.rs
+152
-25
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed/post.rs
+152
-25
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/feed/post.rs
···
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
+
1
8
///Deprecated: use facets instead.
9
+
#[jacquard_derive::lexicon]
2
10
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
3
11
#[serde(rename_all = "camelCase")]
4
12
pub struct Entity<'a> {
5
-
pub index: jacquard_common::types::value::Data<'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)]
6
17
pub r#type: jacquard_common::CowStr<'a>,
18
+
#[serde(borrow)]
7
19
pub value: jacquard_common::CowStr<'a>,
8
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
+
9
34
///Record containing a Bluesky post.
10
35
#[jacquard_derive::lexicon]
11
36
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
12
37
#[serde(rename_all = "camelCase")]
13
38
pub struct Post<'a> {
39
+
///Client-declared timestamp when this post was originally created.
14
40
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>>>,
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)]
29
72
pub text: jacquard_common::CowStr<'a>,
30
73
}
74
+
31
75
#[jacquard_derive::open_union]
32
76
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
33
77
#[serde(tag = "$type")]
34
-
pub enum RecordEmbed<'a> {
78
+
#[serde(bound(deserialize = "'de: 'a"))]
79
+
pub enum PostRecordEmbed<'a> {
35
80
#[serde(rename = "app.bsky.embed.images")]
36
-
Images(Box<test_generated::app_bsky::embed::Images<'a>>),
81
+
Images(Box<test_generated::app_bsky::embed::images::Images<'a>>),
37
82
#[serde(rename = "app.bsky.embed.video")]
38
-
Video(Box<test_generated::app_bsky::embed::Video<'a>>),
83
+
Video(Box<test_generated::app_bsky::embed::video::Video<'a>>),
39
84
#[serde(rename = "app.bsky.embed.external")]
40
-
External(Box<test_generated::app_bsky::embed::External<'a>>),
85
+
External(Box<test_generated::app_bsky::embed::external::ExternalRecord<'a>>),
41
86
#[serde(rename = "app.bsky.embed.record")]
42
-
Record(Box<test_generated::app_bsky::embed::Record<'a>>),
87
+
Record(Box<test_generated::app_bsky::embed::record::Record<'a>>),
43
88
#[serde(rename = "app.bsky.embed.recordWithMedia")]
44
-
RecordWithMedia(Box<test_generated::app_bsky::embed::RecordWithMedia<'a>>),
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
+
}
45
108
}
109
+
46
110
#[jacquard_derive::open_union]
47
111
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
48
112
#[serde(tag = "$type")]
49
-
pub enum RecordLabels<'a> {
113
+
#[serde(bound(deserialize = "'de: 'a"))]
114
+
pub enum PostRecordLabels<'a> {
50
115
#[serde(rename = "com.atproto.label.defs#selfLabels")]
51
-
SelfLabels(Box<test_generated::com_atproto::label::SelfLabels<'a>>),
116
+
DefsSelfLabels(Box<test_generated::com_atproto::label::SelfLabels<'a>>),
52
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]
53
154
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
54
155
#[serde(rename_all = "camelCase")]
55
156
pub struct ReplyRef<'a> {
56
-
pub parent: test_generated::com_atproto::repo::StrongRef<'a>,
57
-
pub root: test_generated::com_atproto::repo::StrongRef<'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>,
58
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
+
59
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]
60
176
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
61
177
#[serde(rename_all = "camelCase")]
62
178
pub struct TextSlice<'a> {
63
179
pub end: i64,
64
180
pub start: i64,
65
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
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/richtext.rs
+74
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/richtext/facet.rs
+74
-1
crates/jacquard-lexicon/target/test_codegen_output/app_bsky/richtext/facet.rs
···
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
+
1
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]
2
10
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
3
11
#[serde(rename_all = "camelCase")]
4
12
pub struct ByteSlice<'a> {
5
13
pub byte_end: i64,
6
14
pub byte_start: i64,
7
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
+
8
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]
9
30
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
10
31
#[serde(rename_all = "camelCase")]
11
32
pub struct Link<'a> {
33
+
#[serde(borrow)]
12
34
pub uri: jacquard_common::types::string::Uri<'a>,
13
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
+
14
47
///Annotation of a sub-string within rich text.
48
+
#[jacquard_derive::lexicon]
15
49
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
16
50
#[serde(rename_all = "camelCase")]
17
51
pub struct Facet<'a> {
52
+
#[serde(borrow)]
18
53
pub features: Vec<jacquard_common::types::value::Data<'a>>,
19
-
pub index: 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
+
}
20
67
}
68
+
21
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]
22
71
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
23
72
#[serde(rename_all = "camelCase")]
24
73
pub struct Mention<'a> {
74
+
#[serde(borrow)]
25
75
pub did: jacquard_common::types::string::Did<'a>,
26
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
+
27
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]
28
90
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
29
91
#[serde(rename_all = "camelCase")]
30
92
pub struct Tag<'a> {
93
+
#[serde(borrow)]
31
94
pub tag: jacquard_common::CowStr<'a>,
32
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
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/com_atproto.rs
+157
-28
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/label.rs
+157
-28
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/label.rs
···
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
+
1
8
///Metadata tag on an atproto resource (eg, repo or record).
9
+
#[jacquard_derive::lexicon]
2
10
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
3
11
#[serde(rename_all = "camelCase")]
4
12
pub struct Label<'a> {
5
-
#[serde(skip_serializing_if = "Option::is_none")]
6
-
pub cid: Option<jacquard_common::types::string::Cid<'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.
7
18
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>,
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)]
14
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)]
15
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)]
16
36
pub val: jacquard_common::CowStr<'a>,
17
-
#[serde(skip_serializing_if = "Option::is_none")]
18
-
pub ver: Option<i64>,
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
+
}
19
58
}
59
+
20
60
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
21
61
pub enum LabelValue<'a> {
22
-
#[serde(rename = "!hide")]
23
62
Hide,
24
-
#[serde(rename = "!no-promote")]
25
63
NoPromote,
26
-
#[serde(rename = "!warn")]
27
64
Warn,
28
-
#[serde(rename = "!no-unauthenticated")]
29
65
NoUnauthenticated,
30
-
#[serde(rename = "dmca-violation")]
31
66
DmcaViolation,
32
-
#[serde(rename = "doxxing")]
33
67
Doxxing,
34
-
#[serde(rename = "porn")]
35
68
Porn,
36
-
#[serde(rename = "sexual")]
37
69
Sexual,
38
-
#[serde(rename = "nudity")]
39
70
Nudity,
40
-
#[serde(rename = "nsfl")]
41
71
Nsfl,
42
-
#[serde(rename = "gore")]
43
72
Gore,
44
-
#[serde(untagged)]
45
73
Other(jacquard_common::CowStr<'a>),
46
74
}
75
+
47
76
impl<'a> LabelValue<'a> {
48
77
pub fn as_str(&self) -> &str {
49
78
match self {
···
62
91
}
63
92
}
64
93
}
94
+
65
95
impl<'a> From<&'a str> for LabelValue<'a> {
66
96
fn from(s: &'a str) -> Self {
67
97
match s {
···
80
110
}
81
111
}
82
112
}
113
+
83
114
impl<'a> From<String> for LabelValue<'a> {
84
115
fn from(s: String) -> Self {
85
116
match s.as_str() {
···
98
129
}
99
130
}
100
131
}
132
+
101
133
impl<'a> AsRef<str> for LabelValue<'a> {
102
134
fn as_ref(&self) -> &str {
103
135
self.as_str()
104
136
}
105
137
}
138
+
106
139
impl<'a> serde::Serialize for LabelValue<'a> {
107
140
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
108
141
where
···
111
144
serializer.serialize_str(self.as_str())
112
145
}
113
146
}
147
+
114
148
impl<'de, 'a> serde::Deserialize<'de> for LabelValue<'a>
115
149
where
116
150
'de: 'a,
···
123
157
Ok(Self::from(s))
124
158
}
125
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
+
126
181
///Declares a label value and its expected interpretations and behaviors.
182
+
#[jacquard_derive::lexicon]
127
183
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
128
184
#[serde(rename_all = "camelCase")]
129
185
pub struct LabelValueDefinition<'a> {
130
-
#[serde(skip_serializing_if = "Option::is_none")]
131
-
pub adult_only: Option<bool>,
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)]
132
191
pub blurs: jacquard_common::CowStr<'a>,
133
-
#[serde(skip_serializing_if = "Option::is_none")]
134
-
pub default_setting: Option<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)]
135
198
pub identifier: jacquard_common::CowStr<'a>,
136
-
pub locales: Vec<jacquard_common::types::value::Data<'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)]
137
205
pub severity: jacquard_common::CowStr<'a>,
138
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
+
139
223
///Strings which describe the label in the UI, localized into a specific language.
224
+
#[jacquard_derive::lexicon]
140
225
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
141
226
#[serde(rename_all = "camelCase")]
142
227
pub struct LabelValueDefinitionStrings<'a> {
228
+
///A longer description of what the label means and why it might be applied.
229
+
#[serde(borrow)]
143
230
pub description: jacquard_common::CowStr<'a>,
231
+
///The code of the language these strings are written in.
144
232
pub lang: jacquard_common::types::string::Language,
233
+
///A short human-readable name for the label.
234
+
#[serde(borrow)]
145
235
pub name: jacquard_common::CowStr<'a>,
146
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
+
147
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]
148
252
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
149
253
#[serde(rename_all = "camelCase")]
150
254
pub struct SelfLabel<'a> {
255
+
///The short string name of the value or type of this label.
256
+
#[serde(borrow)]
151
257
pub val: jacquard_common::CowStr<'a>,
152
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
+
153
270
///Metadata tags on an atproto record, published by the author within the record.
271
+
#[jacquard_derive::lexicon]
154
272
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
155
273
#[serde(rename_all = "camelCase")]
156
274
pub struct SelfLabels<'a> {
157
-
pub values: Vec<jacquard_common::types::value::Data<'a>>,
275
+
#[serde(borrow)]
276
+
pub values: Vec<test_generated::com_atproto::label::SelfLabel<'a>>,
158
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
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/repo.rs
+21
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/repo/strong_ref.rs
+21
crates/jacquard-lexicon/target/test_codegen_output/com_atproto/repo/strong_ref.rs
···
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]
1
9
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
2
10
#[serde(rename_all = "camelCase")]
3
11
pub struct StrongRef<'a> {
12
+
#[serde(borrow)]
4
13
pub cid: jacquard_common::types::string::Cid<'a>,
14
+
#[serde(borrow)]
5
15
pub uri: jacquard_common::types::string::AtUri<'a>,
6
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
+6
-1
crates/jacquard-lexicon/target/test_codegen_output/lib.rs
+149
-25
crates/jacquard/src/client.rs
+149
-25
crates/jacquard/src/client.rs
···
4
4
use std::fmt::Display;
5
5
use std::future::Future;
6
6
7
-
pub use error::{ClientError, Result};
8
7
use bytes::Bytes;
8
+
pub use error::{ClientError, Result};
9
9
use http::{
10
10
HeaderName, HeaderValue, Request,
11
11
header::{AUTHORIZATION, CONTENT_TYPE, InvalidHeaderValue},
12
12
};
13
13
pub use response::Response;
14
-
use serde::Serialize;
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();
15
33
16
-
use jacquard_common::{CowStr, types::xrpc::{XrpcMethod, XrpcRequest}};
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
+
}
17
58
18
59
pub trait HttpClient {
19
60
type Error: std::error::Error + Display + Send + Sync + 'static;
···
98
139
99
140
// Add query parameters for Query methods
100
141
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
-
}
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);
106
146
}
107
147
}
108
148
···
139
179
}
140
180
141
181
// 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
-
}
182
+
let body = if let XrpcMethod::Procedure(_) = R::METHOD {
183
+
request.encode_body()?
149
184
} else {
150
185
vec![]
151
186
};
152
187
188
+
// TODO: make this not panic
153
189
let http_request = builder.body(body).expect("Failed to build HTTP request");
154
190
155
191
// Send HTTP request
156
-
let http_response = client.send_http(http_request).await.map_err(|e| {
157
-
error::TransportError::Other(Box::new(e))
158
-
})?;
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());
159
199
160
-
// Check status
161
-
if !http_response.status().is_success() {
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) {
162
203
return Err(ClientError::Http(error::HttpError {
163
-
status: http_response.status(),
164
-
body: Some(Bytes::from(http_response.body().clone())),
204
+
status,
205
+
body: Some(buffer),
165
206
}));
166
207
}
167
208
168
-
// Convert to Response
169
-
let buffer = Bytes::from(http_response.into_body());
170
-
Ok(Response::new(buffer))
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
+
}
171
295
}
+2
-15
crates/jacquard/src/client/error.rs
+2
-15
crates/jacquard/src/client/error.rs
···
59
59
Other(Box<dyn std::error::Error + Send + Sync>),
60
60
}
61
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
-
}
62
+
// Re-export EncodeError from common
63
+
pub use jacquard_common::types::xrpc::EncodeError;
77
64
78
65
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
79
66
pub enum DecodeError {
+109
-12
crates/jacquard/src/client/response.rs
+109
-12
crates/jacquard/src/client/response.rs
···
1
1
use bytes::Bytes;
2
+
use http::StatusCode;
2
3
use jacquard_common::IntoStatic;
3
4
use jacquard_common::types::xrpc::XrpcRequest;
5
+
use serde::Deserialize;
4
6
use std::marker::PhantomData;
7
+
8
+
use super::error::AuthError;
5
9
6
10
/// XRPC response wrapper that owns the response buffer
7
11
///
8
12
/// Allows borrowing from the buffer when parsing to avoid unnecessary allocations.
9
13
pub struct Response<R: XrpcRequest> {
10
14
buffer: Bytes,
15
+
status: StatusCode,
11
16
_marker: PhantomData<R>,
12
17
}
13
18
14
19
impl<R: XrpcRequest> Response<R> {
15
-
/// Create a new response from a buffer
16
-
pub fn new(buffer: Bytes) -> Self {
20
+
/// Create a new response from a buffer and status code
21
+
pub fn new(buffer: Bytes, status: StatusCode) -> Self {
17
22
Self {
18
23
buffer,
24
+
status,
19
25
_marker: PhantomData,
20
26
}
27
+
}
28
+
29
+
/// Get the HTTP status code
30
+
pub fn status(&self) -> StatusCode {
31
+
self.status
21
32
}
22
33
23
34
/// Parse the response, borrowing from the internal buffer
···
35
46
serde_json::from_slice(buffer)
36
47
}
37
48
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
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 {
43
57
match parse_error::<R>(&self.buffer) {
44
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
+
}
45
84
Err(e) => Err(XrpcError::Decode(e)),
46
85
}
47
86
}
···
66
105
serde_json::from_slice(buffer)
67
106
}
68
107
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
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 {
74
116
match parse_error::<R>(&self.buffer) {
75
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
+
}
76
143
Err(e) => Err(XrpcError::Decode(e)),
77
144
}
78
145
}
···
84
151
}
85
152
}
86
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
+
87
173
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
88
174
pub enum XrpcError<E: std::error::Error + IntoStatic> {
175
+
/// Typed XRPC error from the endpoint's error enum
89
176
#[error("XRPC error: {0}")]
90
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
91
188
#[error("Failed to decode response: {0}")]
92
189
Decode(#[from] serde_json::Error),
93
190
}