Skip to main content

jacquard_api/app_bsky/feed/
generator.rs

1// @generated by jacquard-lexicon. DO NOT EDIT.
2//
3// Lexicon: app.bsky.feed.generator
4//
5// This file was automatically generated from Lexicon schemas.
6// Any manual changes will be overwritten on the next regeneration.
7
8#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::CowStr;
14
15#[allow(unused_imports)]
16use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
17use jacquard_common::types::blob::BlobRef;
18use jacquard_common::types::collection::{Collection, RecordError};
19use jacquard_common::types::string::{Did, AtUri, Cid, Datetime};
20use jacquard_common::types::uri::{RecordUri, UriError};
21use jacquard_common::xrpc::XrpcResp;
22use jacquard_derive::{IntoStatic, lexicon};
23use jacquard_lexicon::lexicon::LexiconDoc;
24use jacquard_lexicon::schema::LexiconSchema;
25
26#[allow(unused_imports)]
27use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
28use serde::{Serialize, Deserialize};
29use crate::app_bsky::richtext::facet::Facet;
30use crate::com_atproto::label::SelfLabels;
31/// Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.
32
33#[lexicon]
34#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
35#[serde(rename_all = "camelCase", rename = "app.bsky.feed.generator", tag = "$type")]
36pub struct Generator<'a> {
37    ///Declaration that a feed accepts feedback interactions from a client through app.bsky.feed.sendInteractions
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub accepts_interactions: Option<bool>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    #[serde(borrow)]
42    pub avatar: Option<BlobRef<'a>>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    #[serde(borrow)]
45    pub content_mode: Option<GeneratorContentMode<'a>>,
46    pub created_at: Datetime,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    #[serde(borrow)]
49    pub description: Option<CowStr<'a>>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    #[serde(borrow)]
52    pub description_facets: Option<Vec<Facet<'a>>>,
53    #[serde(borrow)]
54    pub did: Did<'a>,
55    #[serde(borrow)]
56    pub display_name: CowStr<'a>,
57    ///Self-label values
58    #[serde(skip_serializing_if = "Option::is_none")]
59    #[serde(borrow)]
60    pub labels: Option<SelfLabels<'a>>,
61}
62
63
64#[derive(Debug, Clone, PartialEq, Eq, Hash)]
65pub enum GeneratorContentMode<'a> {
66    ContentModeUnspecified,
67    ContentModeVideo,
68    Other(CowStr<'a>),
69}
70
71impl<'a> GeneratorContentMode<'a> {
72    pub fn as_str(&self) -> &str {
73        match self {
74            Self::ContentModeUnspecified => "app.bsky.feed.defs#contentModeUnspecified",
75            Self::ContentModeVideo => "app.bsky.feed.defs#contentModeVideo",
76            Self::Other(s) => s.as_ref(),
77        }
78    }
79}
80
81impl<'a> From<&'a str> for GeneratorContentMode<'a> {
82    fn from(s: &'a str) -> Self {
83        match s {
84            "app.bsky.feed.defs#contentModeUnspecified" => Self::ContentModeUnspecified,
85            "app.bsky.feed.defs#contentModeVideo" => Self::ContentModeVideo,
86            _ => Self::Other(CowStr::from(s)),
87        }
88    }
89}
90
91impl<'a> From<String> for GeneratorContentMode<'a> {
92    fn from(s: String) -> Self {
93        match s.as_str() {
94            "app.bsky.feed.defs#contentModeUnspecified" => Self::ContentModeUnspecified,
95            "app.bsky.feed.defs#contentModeVideo" => Self::ContentModeVideo,
96            _ => Self::Other(CowStr::from(s)),
97        }
98    }
99}
100
101impl<'a> core::fmt::Display for GeneratorContentMode<'a> {
102    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103        write!(f, "{}", self.as_str())
104    }
105}
106
107impl<'a> AsRef<str> for GeneratorContentMode<'a> {
108    fn as_ref(&self) -> &str {
109        self.as_str()
110    }
111}
112
113impl<'a> serde::Serialize for GeneratorContentMode<'a> {
114    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115    where
116        S: serde::Serializer,
117    {
118        serializer.serialize_str(self.as_str())
119    }
120}
121
122impl<'de, 'a> serde::Deserialize<'de> for GeneratorContentMode<'a>
123where
124    'de: 'a,
125{
126    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
127    where
128        D: serde::Deserializer<'de>,
129    {
130        let s = <&'de str>::deserialize(deserializer)?;
131        Ok(Self::from(s))
132    }
133}
134
135impl<'a> Default for GeneratorContentMode<'a> {
136    fn default() -> Self {
137        Self::Other(Default::default())
138    }
139}
140
141impl jacquard_common::IntoStatic for GeneratorContentMode<'_> {
142    type Output = GeneratorContentMode<'static>;
143    fn into_static(self) -> Self::Output {
144        match self {
145            GeneratorContentMode::ContentModeUnspecified => {
146                GeneratorContentMode::ContentModeUnspecified
147            }
148            GeneratorContentMode::ContentModeVideo => {
149                GeneratorContentMode::ContentModeVideo
150            }
151            GeneratorContentMode::Other(v) => {
152                GeneratorContentMode::Other(v.into_static())
153            }
154        }
155    }
156}
157
158/// Typed wrapper for GetRecord response with this collection's record type.
159
160#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
161#[serde(rename_all = "camelCase")]
162pub struct GeneratorGetRecordOutput<'a> {
163    #[serde(skip_serializing_if = "Option::is_none")]
164    #[serde(borrow)]
165    pub cid: Option<Cid<'a>>,
166    #[serde(borrow)]
167    pub uri: AtUri<'a>,
168    #[serde(borrow)]
169    pub value: Generator<'a>,
170}
171
172impl<'a> Generator<'a> {
173    pub fn uri(
174        uri: impl Into<CowStr<'a>>,
175    ) -> Result<RecordUri<'a, GeneratorRecord>, UriError> {
176        RecordUri::try_from_uri(AtUri::new_cow(uri.into())?)
177    }
178}
179
180/// Marker type for deserializing records from this collection.
181
182#[derive(Debug, Serialize, Deserialize)]
183pub struct GeneratorRecord;
184impl XrpcResp for GeneratorRecord {
185    const NSID: &'static str = "app.bsky.feed.generator";
186    const ENCODING: &'static str = "application/json";
187    type Output<'de> = GeneratorGetRecordOutput<'de>;
188    type Err<'de> = RecordError<'de>;
189}
190
191impl From<GeneratorGetRecordOutput<'_>> for Generator<'_> {
192    fn from(output: GeneratorGetRecordOutput<'_>) -> Self {
193        use jacquard_common::IntoStatic;
194        output.value.into_static()
195    }
196}
197
198impl Collection for Generator<'_> {
199    const NSID: &'static str = "app.bsky.feed.generator";
200    type Record = GeneratorRecord;
201}
202
203impl Collection for GeneratorRecord {
204    const NSID: &'static str = "app.bsky.feed.generator";
205    type Record = GeneratorRecord;
206}
207
208impl<'a> LexiconSchema for Generator<'a> {
209    fn nsid() -> &'static str {
210        "app.bsky.feed.generator"
211    }
212    fn def_name() -> &'static str {
213        "main"
214    }
215    fn lexicon_doc() -> LexiconDoc<'static> {
216        lexicon_doc_app_bsky_feed_generator()
217    }
218    fn validate(&self) -> Result<(), ConstraintError> {
219        if let Some(ref value) = self.avatar {
220            {
221                let size = value.blob().size;
222                if size > 1000000usize {
223                    return Err(ConstraintError::BlobTooLarge {
224                        path: ValidationPath::from_field("avatar"),
225                        max: 1000000usize,
226                        actual: size,
227                    });
228                }
229            }
230        }
231        if let Some(ref value) = self.avatar {
232            {
233                let mime = value.blob().mime_type.as_str();
234                let accepted: &[&str] = &["image/png", "image/jpeg"];
235                let matched = accepted
236                    .iter()
237                    .any(|pattern| {
238                        if *pattern == "*/*" {
239                            true
240                        } else if pattern.ends_with("/*") {
241                            let prefix = &pattern[..pattern.len() - 2];
242                            mime.starts_with(prefix)
243                                && mime.as_bytes().get(prefix.len()) == Some(&b'/')
244                        } else {
245                            mime == *pattern
246                        }
247                    });
248                if !matched {
249                    return Err(ConstraintError::BlobMimeTypeNotAccepted {
250                        path: ValidationPath::from_field("avatar"),
251                        accepted: vec![
252                            "image/png".to_string(), "image/jpeg".to_string()
253                        ],
254                        actual: mime.to_string(),
255                    });
256                }
257            }
258        }
259        if let Some(ref value) = self.description {
260            #[allow(unused_comparisons)]
261            if <str>::len(value.as_ref()) > 3000usize {
262                return Err(ConstraintError::MaxLength {
263                    path: ValidationPath::from_field("description"),
264                    max: 3000usize,
265                    actual: <str>::len(value.as_ref()),
266                });
267            }
268        }
269        if let Some(ref value) = self.description {
270            {
271                let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
272                if count > 300usize {
273                    return Err(ConstraintError::MaxGraphemes {
274                        path: ValidationPath::from_field("description"),
275                        max: 300usize,
276                        actual: count,
277                    });
278                }
279            }
280        }
281        {
282            let value = &self.display_name;
283            #[allow(unused_comparisons)]
284            if <str>::len(value.as_ref()) > 240usize {
285                return Err(ConstraintError::MaxLength {
286                    path: ValidationPath::from_field("display_name"),
287                    max: 240usize,
288                    actual: <str>::len(value.as_ref()),
289                });
290            }
291        }
292        {
293            let value = &self.display_name;
294            {
295                let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
296                if count > 24usize {
297                    return Err(ConstraintError::MaxGraphemes {
298                        path: ValidationPath::from_field("display_name"),
299                        max: 24usize,
300                        actual: count,
301                    });
302                }
303            }
304        }
305        Ok(())
306    }
307}
308
309pub mod generator_state {
310
311    pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
312    #[allow(unused)]
313    use ::core::marker::PhantomData;
314    mod sealed {
315        pub trait Sealed {}
316    }
317    /// State trait tracking which required fields have been set
318    pub trait State: sealed::Sealed {
319        type DisplayName;
320        type CreatedAt;
321        type Did;
322    }
323    /// Empty state - all required fields are unset
324    pub struct Empty(());
325    impl sealed::Sealed for Empty {}
326    impl State for Empty {
327        type DisplayName = Unset;
328        type CreatedAt = Unset;
329        type Did = Unset;
330    }
331    ///State transition - sets the `display_name` field to Set
332    pub struct SetDisplayName<S: State = Empty>(PhantomData<fn() -> S>);
333    impl<S: State> sealed::Sealed for SetDisplayName<S> {}
334    impl<S: State> State for SetDisplayName<S> {
335        type DisplayName = Set<members::display_name>;
336        type CreatedAt = S::CreatedAt;
337        type Did = S::Did;
338    }
339    ///State transition - sets the `created_at` field to Set
340    pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
341    impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
342    impl<S: State> State for SetCreatedAt<S> {
343        type DisplayName = S::DisplayName;
344        type CreatedAt = Set<members::created_at>;
345        type Did = S::Did;
346    }
347    ///State transition - sets the `did` field to Set
348    pub struct SetDid<S: State = Empty>(PhantomData<fn() -> S>);
349    impl<S: State> sealed::Sealed for SetDid<S> {}
350    impl<S: State> State for SetDid<S> {
351        type DisplayName = S::DisplayName;
352        type CreatedAt = S::CreatedAt;
353        type Did = Set<members::did>;
354    }
355    /// Marker types for field names
356    #[allow(non_camel_case_types)]
357    pub mod members {
358        ///Marker type for the `display_name` field
359        pub struct display_name(());
360        ///Marker type for the `created_at` field
361        pub struct created_at(());
362        ///Marker type for the `did` field
363        pub struct did(());
364    }
365}
366
367/// Builder for constructing an instance of this type
368pub struct GeneratorBuilder<'a, S: generator_state::State> {
369    _state: PhantomData<fn() -> S>,
370    _fields: (
371        Option<bool>,
372        Option<BlobRef<'a>>,
373        Option<GeneratorContentMode<'a>>,
374        Option<Datetime>,
375        Option<CowStr<'a>>,
376        Option<Vec<Facet<'a>>>,
377        Option<Did<'a>>,
378        Option<CowStr<'a>>,
379        Option<SelfLabels<'a>>,
380    ),
381    _lifetime: PhantomData<&'a ()>,
382}
383
384impl<'a> Generator<'a> {
385    /// Create a new builder for this type
386    pub fn new() -> GeneratorBuilder<'a, generator_state::Empty> {
387        GeneratorBuilder::new()
388    }
389}
390
391impl<'a> GeneratorBuilder<'a, generator_state::Empty> {
392    /// Create a new builder with all fields unset
393    pub fn new() -> Self {
394        GeneratorBuilder {
395            _state: PhantomData,
396            _fields: (None, None, None, None, None, None, None, None, None),
397            _lifetime: PhantomData,
398        }
399    }
400}
401
402impl<'a, S: generator_state::State> GeneratorBuilder<'a, S> {
403    /// Set the `acceptsInteractions` field (optional)
404    pub fn accepts_interactions(mut self, value: impl Into<Option<bool>>) -> Self {
405        self._fields.0 = value.into();
406        self
407    }
408    /// Set the `acceptsInteractions` field to an Option value (optional)
409    pub fn maybe_accepts_interactions(mut self, value: Option<bool>) -> Self {
410        self._fields.0 = value;
411        self
412    }
413}
414
415impl<'a, S: generator_state::State> GeneratorBuilder<'a, S> {
416    /// Set the `avatar` field (optional)
417    pub fn avatar(mut self, value: impl Into<Option<BlobRef<'a>>>) -> Self {
418        self._fields.1 = value.into();
419        self
420    }
421    /// Set the `avatar` field to an Option value (optional)
422    pub fn maybe_avatar(mut self, value: Option<BlobRef<'a>>) -> Self {
423        self._fields.1 = value;
424        self
425    }
426}
427
428impl<'a, S: generator_state::State> GeneratorBuilder<'a, S> {
429    /// Set the `contentMode` field (optional)
430    pub fn content_mode(
431        mut self,
432        value: impl Into<Option<GeneratorContentMode<'a>>>,
433    ) -> Self {
434        self._fields.2 = value.into();
435        self
436    }
437    /// Set the `contentMode` field to an Option value (optional)
438    pub fn maybe_content_mode(
439        mut self,
440        value: Option<GeneratorContentMode<'a>>,
441    ) -> Self {
442        self._fields.2 = value;
443        self
444    }
445}
446
447impl<'a, S> GeneratorBuilder<'a, S>
448where
449    S: generator_state::State,
450    S::CreatedAt: generator_state::IsUnset,
451{
452    /// Set the `createdAt` field (required)
453    pub fn created_at(
454        mut self,
455        value: impl Into<Datetime>,
456    ) -> GeneratorBuilder<'a, generator_state::SetCreatedAt<S>> {
457        self._fields.3 = Option::Some(value.into());
458        GeneratorBuilder {
459            _state: PhantomData,
460            _fields: self._fields,
461            _lifetime: PhantomData,
462        }
463    }
464}
465
466impl<'a, S: generator_state::State> GeneratorBuilder<'a, S> {
467    /// Set the `description` field (optional)
468    pub fn description(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
469        self._fields.4 = value.into();
470        self
471    }
472    /// Set the `description` field to an Option value (optional)
473    pub fn maybe_description(mut self, value: Option<CowStr<'a>>) -> Self {
474        self._fields.4 = value;
475        self
476    }
477}
478
479impl<'a, S: generator_state::State> GeneratorBuilder<'a, S> {
480    /// Set the `descriptionFacets` field (optional)
481    pub fn description_facets(
482        mut self,
483        value: impl Into<Option<Vec<Facet<'a>>>>,
484    ) -> Self {
485        self._fields.5 = value.into();
486        self
487    }
488    /// Set the `descriptionFacets` field to an Option value (optional)
489    pub fn maybe_description_facets(mut self, value: Option<Vec<Facet<'a>>>) -> Self {
490        self._fields.5 = value;
491        self
492    }
493}
494
495impl<'a, S> GeneratorBuilder<'a, S>
496where
497    S: generator_state::State,
498    S::Did: generator_state::IsUnset,
499{
500    /// Set the `did` field (required)
501    pub fn did(
502        mut self,
503        value: impl Into<Did<'a>>,
504    ) -> GeneratorBuilder<'a, generator_state::SetDid<S>> {
505        self._fields.6 = Option::Some(value.into());
506        GeneratorBuilder {
507            _state: PhantomData,
508            _fields: self._fields,
509            _lifetime: PhantomData,
510        }
511    }
512}
513
514impl<'a, S> GeneratorBuilder<'a, S>
515where
516    S: generator_state::State,
517    S::DisplayName: generator_state::IsUnset,
518{
519    /// Set the `displayName` field (required)
520    pub fn display_name(
521        mut self,
522        value: impl Into<CowStr<'a>>,
523    ) -> GeneratorBuilder<'a, generator_state::SetDisplayName<S>> {
524        self._fields.7 = Option::Some(value.into());
525        GeneratorBuilder {
526            _state: PhantomData,
527            _fields: self._fields,
528            _lifetime: PhantomData,
529        }
530    }
531}
532
533impl<'a, S: generator_state::State> GeneratorBuilder<'a, S> {
534    /// Set the `labels` field (optional)
535    pub fn labels(mut self, value: impl Into<Option<SelfLabels<'a>>>) -> Self {
536        self._fields.8 = value.into();
537        self
538    }
539    /// Set the `labels` field to an Option value (optional)
540    pub fn maybe_labels(mut self, value: Option<SelfLabels<'a>>) -> Self {
541        self._fields.8 = value;
542        self
543    }
544}
545
546impl<'a, S> GeneratorBuilder<'a, S>
547where
548    S: generator_state::State,
549    S::DisplayName: generator_state::IsSet,
550    S::CreatedAt: generator_state::IsSet,
551    S::Did: generator_state::IsSet,
552{
553    /// Build the final struct
554    pub fn build(self) -> Generator<'a> {
555        Generator {
556            accepts_interactions: self._fields.0,
557            avatar: self._fields.1,
558            content_mode: self._fields.2,
559            created_at: self._fields.3.unwrap(),
560            description: self._fields.4,
561            description_facets: self._fields.5,
562            did: self._fields.6.unwrap(),
563            display_name: self._fields.7.unwrap(),
564            labels: self._fields.8,
565            extra_data: Default::default(),
566        }
567    }
568    /// Build the final struct with custom extra_data
569    pub fn build_with_data(
570        self,
571        extra_data: BTreeMap<
572            jacquard_common::deps::smol_str::SmolStr,
573            jacquard_common::types::value::Data<'a>,
574        >,
575    ) -> Generator<'a> {
576        Generator {
577            accepts_interactions: self._fields.0,
578            avatar: self._fields.1,
579            content_mode: self._fields.2,
580            created_at: self._fields.3.unwrap(),
581            description: self._fields.4,
582            description_facets: self._fields.5,
583            did: self._fields.6.unwrap(),
584            display_name: self._fields.7.unwrap(),
585            labels: self._fields.8,
586            extra_data: Some(extra_data),
587        }
588    }
589}
590
591fn lexicon_doc_app_bsky_feed_generator() -> LexiconDoc<'static> {
592    #[allow(unused_imports)]
593    use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
594    use jacquard_lexicon::lexicon::*;
595    use alloc::collections::BTreeMap;
596    LexiconDoc {
597        lexicon: Lexicon::Lexicon1,
598        id: CowStr::new_static("app.bsky.feed.generator"),
599        defs: {
600            let mut map = BTreeMap::new();
601            map.insert(
602                SmolStr::new_static("main"),
603                LexUserType::Record(LexRecord {
604                    description: Some(
605                        CowStr::new_static(
606                            "Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository.",
607                        ),
608                    ),
609                    key: Some(CowStr::new_static("any")),
610                    record: LexRecordRecord::Object(LexObject {
611                        required: Some(
612                            vec![
613                                SmolStr::new_static("did"),
614                                SmolStr::new_static("displayName"),
615                                SmolStr::new_static("createdAt")
616                            ],
617                        ),
618                        properties: {
619                            #[allow(unused_mut)]
620                            let mut map = BTreeMap::new();
621                            map.insert(
622                                SmolStr::new_static("acceptsInteractions"),
623                                LexObjectProperty::Boolean(LexBoolean {
624                                    ..Default::default()
625                                }),
626                            );
627                            map.insert(
628                                SmolStr::new_static("avatar"),
629                                LexObjectProperty::Blob(LexBlob { ..Default::default() }),
630                            );
631                            map.insert(
632                                SmolStr::new_static("contentMode"),
633                                LexObjectProperty::String(LexString {
634                                    ..Default::default()
635                                }),
636                            );
637                            map.insert(
638                                SmolStr::new_static("createdAt"),
639                                LexObjectProperty::String(LexString {
640                                    format: Some(LexStringFormat::Datetime),
641                                    ..Default::default()
642                                }),
643                            );
644                            map.insert(
645                                SmolStr::new_static("description"),
646                                LexObjectProperty::String(LexString {
647                                    max_length: Some(3000usize),
648                                    max_graphemes: Some(300usize),
649                                    ..Default::default()
650                                }),
651                            );
652                            map.insert(
653                                SmolStr::new_static("descriptionFacets"),
654                                LexObjectProperty::Array(LexArray {
655                                    items: LexArrayItem::Ref(LexRef {
656                                        r#ref: CowStr::new_static("app.bsky.richtext.facet"),
657                                        ..Default::default()
658                                    }),
659                                    ..Default::default()
660                                }),
661                            );
662                            map.insert(
663                                SmolStr::new_static("did"),
664                                LexObjectProperty::String(LexString {
665                                    format: Some(LexStringFormat::Did),
666                                    ..Default::default()
667                                }),
668                            );
669                            map.insert(
670                                SmolStr::new_static("displayName"),
671                                LexObjectProperty::String(LexString {
672                                    max_length: Some(240usize),
673                                    max_graphemes: Some(24usize),
674                                    ..Default::default()
675                                }),
676                            );
677                            map.insert(
678                                SmolStr::new_static("labels"),
679                                LexObjectProperty::Union(LexRefUnion {
680                                    description: Some(CowStr::new_static("Self-label values")),
681                                    refs: vec![
682                                        CowStr::new_static("com.atproto.label.defs#selfLabels")
683                                    ],
684                                    ..Default::default()
685                                }),
686                            );
687                            map
688                        },
689                        ..Default::default()
690                    }),
691                    ..Default::default()
692                }),
693            );
694            map
695        },
696        ..Default::default()
697    }
698}