1#[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};
24use jacquard_lexicon::lexicon::LexiconDoc;
25use jacquard_lexicon::schema::LexiconSchema;
26
27use crate::app_bsky::richtext::facet::Facet;
28use crate::network_slices::tools::Images;
29#[allow(unused_imports)]
30use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
31use serde::{Deserialize, Serialize};
32
33#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
34#[serde(
35 rename_all = "camelCase",
36 rename = "network.slices.tools.bug.comment",
37 tag = "$type",
38 bound(deserialize = "S: Deserialize<'de> + BosStr")
39)]
40pub struct Comment<S: BosStr = DefaultStr> {
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub attachments: Option<Images<S>>,
43 pub body: S,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub body_facets: Option<Vec<Facet<S>>>,
47 pub bug: AtUri<S>,
49 pub created_at: Datetime,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub parent: Option<AtUri<S>>,
53 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
54 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
55}
56
57#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
60#[serde(rename_all = "camelCase")]
61pub struct CommentGetRecordOutput<S: BosStr = DefaultStr> {
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub cid: Option<Cid<S>>,
64 pub uri: AtUri<S>,
65 pub value: Comment<S>,
66}
67
68impl<S: BosStr> Comment<S> {
69 pub fn uri(uri: S) -> Result<RecordUri<S, CommentRecord>, UriError> {
70 RecordUri::try_from_uri(AtUri::new(uri)?)
71 }
72}
73
74#[derive(Debug, Serialize, Deserialize)]
77pub struct CommentRecord;
78impl XrpcResp for CommentRecord {
79 const NSID: &'static str = "network.slices.tools.bug.comment";
80 const ENCODING: &'static str = "application/json";
81 type Output<S: BosStr> = CommentGetRecordOutput<S>;
82 type Err = RecordError;
83}
84
85impl<S: BosStr> From<CommentGetRecordOutput<S>> for Comment<S> {
86 fn from(output: CommentGetRecordOutput<S>) -> Self {
87 output.value
88 }
89}
90
91impl<S: BosStr> Collection for Comment<S> {
92 const NSID: &'static str = "network.slices.tools.bug.comment";
93 type Record = CommentRecord;
94}
95
96impl Collection for CommentRecord {
97 const NSID: &'static str = "network.slices.tools.bug.comment";
98 type Record = CommentRecord;
99}
100
101impl<S: BosStr> LexiconSchema for Comment<S> {
102 fn nsid() -> &'static str {
103 "network.slices.tools.bug.comment"
104 }
105 fn def_name() -> &'static str {
106 "main"
107 }
108 fn lexicon_doc() -> LexiconDoc<'static> {
109 lexicon_doc_network_slices_tools_bug_comment()
110 }
111 fn validate(&self) -> Result<(), ConstraintError> {
112 {
113 let value = &self.body;
114 #[allow(unused_comparisons)]
115 if <str>::len(value.as_ref()) > 10000usize {
116 return Err(ConstraintError::MaxLength {
117 path: ValidationPath::from_field("body"),
118 max: 10000usize,
119 actual: <str>::len(value.as_ref()),
120 });
121 }
122 }
123 {
124 let value = &self.body;
125 {
126 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
127 if count > 3000usize {
128 return Err(ConstraintError::MaxGraphemes {
129 path: ValidationPath::from_field("body"),
130 max: 3000usize,
131 actual: count,
132 });
133 }
134 }
135 }
136 Ok(())
137 }
138}
139
140pub mod comment_state {
141
142 pub use crate::builder_types::{IsSet, IsUnset, Set, Unset};
143 #[allow(unused)]
144 use ::core::marker::PhantomData;
145 mod sealed {
146 pub trait Sealed {}
147 }
148 pub trait State: sealed::Sealed {
150 type Body;
151 type Bug;
152 type CreatedAt;
153 }
154 pub struct Empty(());
156 impl sealed::Sealed for Empty {}
157 impl State for Empty {
158 type Body = Unset;
159 type Bug = Unset;
160 type CreatedAt = Unset;
161 }
162 pub struct SetBody<St: State = Empty>(PhantomData<fn() -> St>);
164 impl<St: State> sealed::Sealed for SetBody<St> {}
165 impl<St: State> State for SetBody<St> {
166 type Body = Set<members::body>;
167 type Bug = St::Bug;
168 type CreatedAt = St::CreatedAt;
169 }
170 pub struct SetBug<St: State = Empty>(PhantomData<fn() -> St>);
172 impl<St: State> sealed::Sealed for SetBug<St> {}
173 impl<St: State> State for SetBug<St> {
174 type Body = St::Body;
175 type Bug = Set<members::bug>;
176 type CreatedAt = St::CreatedAt;
177 }
178 pub struct SetCreatedAt<St: State = Empty>(PhantomData<fn() -> St>);
180 impl<St: State> sealed::Sealed for SetCreatedAt<St> {}
181 impl<St: State> State for SetCreatedAt<St> {
182 type Body = St::Body;
183 type Bug = St::Bug;
184 type CreatedAt = Set<members::created_at>;
185 }
186 #[allow(non_camel_case_types)]
188 pub mod members {
189 pub struct body(());
191 pub struct bug(());
193 pub struct created_at(());
195 }
196}
197
198pub struct CommentBuilder<St: comment_state::State, S: BosStr = DefaultStr> {
200 _state: PhantomData<fn() -> St>,
201 _fields: (
202 Option<Images<S>>,
203 Option<S>,
204 Option<Vec<Facet<S>>>,
205 Option<AtUri<S>>,
206 Option<Datetime>,
207 Option<AtUri<S>>,
208 ),
209 _type: PhantomData<fn() -> S>,
210}
211
212impl Comment<DefaultStr> {
213 pub fn new() -> CommentBuilder<comment_state::Empty, DefaultStr> {
215 CommentBuilder::new()
216 }
217}
218
219impl<S: BosStr> Comment<S> {
220 pub fn builder() -> CommentBuilder<comment_state::Empty, S> {
222 CommentBuilder::builder()
223 }
224}
225
226impl CommentBuilder<comment_state::Empty, DefaultStr> {
227 pub fn new() -> Self {
229 CommentBuilder {
230 _state: PhantomData,
231 _fields: (None, None, None, None, None, None),
232 _type: PhantomData,
233 }
234 }
235}
236
237impl<S: BosStr> CommentBuilder<comment_state::Empty, S> {
238 pub fn builder() -> Self {
240 CommentBuilder {
241 _state: PhantomData,
242 _fields: (None, None, None, None, None, None),
243 _type: PhantomData,
244 }
245 }
246}
247
248impl<St: comment_state::State, S: BosStr> CommentBuilder<St, S> {
249 pub fn attachments(mut self, value: impl Into<Option<Images<S>>>) -> Self {
251 self._fields.0 = value.into();
252 self
253 }
254 pub fn maybe_attachments(mut self, value: Option<Images<S>>) -> Self {
256 self._fields.0 = value;
257 self
258 }
259}
260
261impl<St, S: BosStr> CommentBuilder<St, S>
262where
263 St: comment_state::State,
264 St::Body: comment_state::IsUnset,
265{
266 pub fn body(mut self, value: impl Into<S>) -> CommentBuilder<comment_state::SetBody<St>, S> {
268 self._fields.1 = Option::Some(value.into());
269 CommentBuilder {
270 _state: PhantomData,
271 _fields: self._fields,
272 _type: PhantomData,
273 }
274 }
275}
276
277impl<St: comment_state::State, S: BosStr> CommentBuilder<St, S> {
278 pub fn body_facets(mut self, value: impl Into<Option<Vec<Facet<S>>>>) -> Self {
280 self._fields.2 = value.into();
281 self
282 }
283 pub fn maybe_body_facets(mut self, value: Option<Vec<Facet<S>>>) -> Self {
285 self._fields.2 = value;
286 self
287 }
288}
289
290impl<St, S: BosStr> CommentBuilder<St, S>
291where
292 St: comment_state::State,
293 St::Bug: comment_state::IsUnset,
294{
295 pub fn bug(
297 mut self,
298 value: impl Into<AtUri<S>>,
299 ) -> CommentBuilder<comment_state::SetBug<St>, S> {
300 self._fields.3 = Option::Some(value.into());
301 CommentBuilder {
302 _state: PhantomData,
303 _fields: self._fields,
304 _type: PhantomData,
305 }
306 }
307}
308
309impl<St, S: BosStr> CommentBuilder<St, S>
310where
311 St: comment_state::State,
312 St::CreatedAt: comment_state::IsUnset,
313{
314 pub fn created_at(
316 mut self,
317 value: impl Into<Datetime>,
318 ) -> CommentBuilder<comment_state::SetCreatedAt<St>, S> {
319 self._fields.4 = Option::Some(value.into());
320 CommentBuilder {
321 _state: PhantomData,
322 _fields: self._fields,
323 _type: PhantomData,
324 }
325 }
326}
327
328impl<St: comment_state::State, S: BosStr> CommentBuilder<St, S> {
329 pub fn parent(mut self, value: impl Into<Option<AtUri<S>>>) -> Self {
331 self._fields.5 = value.into();
332 self
333 }
334 pub fn maybe_parent(mut self, value: Option<AtUri<S>>) -> Self {
336 self._fields.5 = value;
337 self
338 }
339}
340
341impl<St, S: BosStr> CommentBuilder<St, S>
342where
343 St: comment_state::State,
344 St::Body: comment_state::IsSet,
345 St::Bug: comment_state::IsSet,
346 St::CreatedAt: comment_state::IsSet,
347{
348 pub fn build(self) -> Comment<S> {
350 Comment {
351 attachments: self._fields.0,
352 body: self._fields.1.unwrap(),
353 body_facets: self._fields.2,
354 bug: self._fields.3.unwrap(),
355 created_at: self._fields.4.unwrap(),
356 parent: self._fields.5,
357 extra_data: Default::default(),
358 }
359 }
360 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Comment<S> {
362 Comment {
363 attachments: self._fields.0,
364 body: self._fields.1.unwrap(),
365 body_facets: self._fields.2,
366 bug: self._fields.3.unwrap(),
367 created_at: self._fields.4.unwrap(),
368 parent: self._fields.5,
369 extra_data: Some(extra_data),
370 }
371 }
372}
373
374fn lexicon_doc_network_slices_tools_bug_comment() -> LexiconDoc<'static> {
375 use alloc::collections::BTreeMap;
376 #[allow(unused_imports)]
377 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
378 use jacquard_lexicon::lexicon::*;
379 LexiconDoc {
380 lexicon: Lexicon::Lexicon1,
381 id: CowStr::new_static("network.slices.tools.bug.comment"),
382 defs: {
383 let mut map = BTreeMap::new();
384 map.insert(
385 SmolStr::new_static("main"),
386 LexUserType::Record(LexRecord {
387 key: Some(CowStr::new_static("tid")),
388 record: LexRecordRecord::Object(LexObject {
389 required: Some(vec![
390 SmolStr::new_static("bug"),
391 SmolStr::new_static("body"),
392 SmolStr::new_static("createdAt"),
393 ]),
394 properties: {
395 #[allow(unused_mut)]
396 let mut map = BTreeMap::new();
397 map.insert(
398 SmolStr::new_static("attachments"),
399 LexObjectProperty::Union(LexRefUnion {
400 refs: vec![CowStr::new_static(
401 "network.slices.tools.defs#images",
402 )],
403 ..Default::default()
404 }),
405 );
406 map.insert(
407 SmolStr::new_static("body"),
408 LexObjectProperty::String(LexString {
409 max_length: Some(10000usize),
410 max_graphemes: Some(3000usize),
411 ..Default::default()
412 }),
413 );
414 map.insert(
415 SmolStr::new_static("bodyFacets"),
416 LexObjectProperty::Array(LexArray {
417 description: Some(CowStr::new_static(
418 "Annotations of body text (mentions and links)",
419 )),
420 items: LexArrayItem::Ref(LexRef {
421 r#ref: CowStr::new_static("app.bsky.richtext.facet"),
422 ..Default::default()
423 }),
424 ..Default::default()
425 }),
426 );
427 map.insert(
428 SmolStr::new_static("bug"),
429 LexObjectProperty::String(LexString {
430 description: Some(CowStr::new_static(
431 "Reference to the bug report",
432 )),
433 format: Some(LexStringFormat::AtUri),
434 ..Default::default()
435 }),
436 );
437 map.insert(
438 SmolStr::new_static("createdAt"),
439 LexObjectProperty::String(LexString {
440 format: Some(LexStringFormat::Datetime),
441 ..Default::default()
442 }),
443 );
444 map.insert(
445 SmolStr::new_static("parent"),
446 LexObjectProperty::String(LexString {
447 description: Some(CowStr::new_static(
448 "Optional reference to parent comment for threading",
449 )),
450 format: Some(LexStringFormat::AtUri),
451 ..Default::default()
452 }),
453 );
454 map
455 },
456 ..Default::default()
457 }),
458 ..Default::default()
459 }),
460 );
461 map
462 },
463 ..Default::default()
464 }
465}