Skip to main content

jacquard_api/app_bsky/feed/
threadgate.rs

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