1#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::{CowStr, BosStr, 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
27#[allow(unused_imports)]
28use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
29use serde::{Serialize, Deserialize};
30use crate::app_bsky::richtext::facet::Facet;
31use crate::network_slices::tools::Images;
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::{Set, Unset, IsSet, IsUnset};
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(
268 mut self,
269 value: impl Into<S>,
270 ) -> CommentBuilder<comment_state::SetBody<St>, S> {
271 self._fields.1 = Option::Some(value.into());
272 CommentBuilder {
273 _state: PhantomData,
274 _fields: self._fields,
275 _type: PhantomData,
276 }
277 }
278}
279
280impl<St: comment_state::State, S: BosStr> CommentBuilder<St, S> {
281 pub fn body_facets(mut self, value: impl Into<Option<Vec<Facet<S>>>>) -> Self {
283 self._fields.2 = value.into();
284 self
285 }
286 pub fn maybe_body_facets(mut self, value: Option<Vec<Facet<S>>>) -> Self {
288 self._fields.2 = value;
289 self
290 }
291}
292
293impl<St, S: BosStr> CommentBuilder<St, S>
294where
295 St: comment_state::State,
296 St::Bug: comment_state::IsUnset,
297{
298 pub fn bug(
300 mut self,
301 value: impl Into<AtUri<S>>,
302 ) -> CommentBuilder<comment_state::SetBug<St>, S> {
303 self._fields.3 = Option::Some(value.into());
304 CommentBuilder {
305 _state: PhantomData,
306 _fields: self._fields,
307 _type: PhantomData,
308 }
309 }
310}
311
312impl<St, S: BosStr> CommentBuilder<St, S>
313where
314 St: comment_state::State,
315 St::CreatedAt: comment_state::IsUnset,
316{
317 pub fn created_at(
319 mut self,
320 value: impl Into<Datetime>,
321 ) -> CommentBuilder<comment_state::SetCreatedAt<St>, S> {
322 self._fields.4 = Option::Some(value.into());
323 CommentBuilder {
324 _state: PhantomData,
325 _fields: self._fields,
326 _type: PhantomData,
327 }
328 }
329}
330
331impl<St: comment_state::State, S: BosStr> CommentBuilder<St, S> {
332 pub fn parent(mut self, value: impl Into<Option<AtUri<S>>>) -> Self {
334 self._fields.5 = value.into();
335 self
336 }
337 pub fn maybe_parent(mut self, value: Option<AtUri<S>>) -> Self {
339 self._fields.5 = value;
340 self
341 }
342}
343
344impl<St, S: BosStr> CommentBuilder<St, S>
345where
346 St: comment_state::State,
347 St::Body: comment_state::IsSet,
348 St::Bug: comment_state::IsSet,
349 St::CreatedAt: comment_state::IsSet,
350{
351 pub fn build(self) -> Comment<S> {
353 Comment {
354 attachments: self._fields.0,
355 body: self._fields.1.unwrap(),
356 body_facets: self._fields.2,
357 bug: self._fields.3.unwrap(),
358 created_at: self._fields.4.unwrap(),
359 parent: self._fields.5,
360 extra_data: Default::default(),
361 }
362 }
363 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Comment<S> {
365 Comment {
366 attachments: self._fields.0,
367 body: self._fields.1.unwrap(),
368 body_facets: self._fields.2,
369 bug: self._fields.3.unwrap(),
370 created_at: self._fields.4.unwrap(),
371 parent: self._fields.5,
372 extra_data: Some(extra_data),
373 }
374 }
375}
376
377fn lexicon_doc_network_slices_tools_bug_comment() -> LexiconDoc<'static> {
378 #[allow(unused_imports)]
379 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
380 use jacquard_lexicon::lexicon::*;
381 use alloc::collections::BTreeMap;
382 LexiconDoc {
383 lexicon: Lexicon::Lexicon1,
384 id: CowStr::new_static("network.slices.tools.bug.comment"),
385 defs: {
386 let mut map = BTreeMap::new();
387 map.insert(
388 SmolStr::new_static("main"),
389 LexUserType::Record(LexRecord {
390 key: Some(CowStr::new_static("tid")),
391 record: LexRecordRecord::Object(LexObject {
392 required: Some(
393 vec![
394 SmolStr::new_static("bug"), SmolStr::new_static("body"),
395 SmolStr::new_static("createdAt")
396 ],
397 ),
398 properties: {
399 #[allow(unused_mut)]
400 let mut map = BTreeMap::new();
401 map.insert(
402 SmolStr::new_static("attachments"),
403 LexObjectProperty::Union(LexRefUnion {
404 refs: vec![
405 CowStr::new_static("network.slices.tools.defs#images")
406 ],
407 ..Default::default()
408 }),
409 );
410 map.insert(
411 SmolStr::new_static("body"),
412 LexObjectProperty::String(LexString {
413 max_length: Some(10000usize),
414 max_graphemes: Some(3000usize),
415 ..Default::default()
416 }),
417 );
418 map.insert(
419 SmolStr::new_static("bodyFacets"),
420 LexObjectProperty::Array(LexArray {
421 description: Some(
422 CowStr::new_static(
423 "Annotations of body text (mentions and links)",
424 ),
425 ),
426 items: LexArrayItem::Ref(LexRef {
427 r#ref: CowStr::new_static("app.bsky.richtext.facet"),
428 ..Default::default()
429 }),
430 ..Default::default()
431 }),
432 );
433 map.insert(
434 SmolStr::new_static("bug"),
435 LexObjectProperty::String(LexString {
436 description: Some(
437 CowStr::new_static("Reference to the bug report"),
438 ),
439 format: Some(LexStringFormat::AtUri),
440 ..Default::default()
441 }),
442 );
443 map.insert(
444 SmolStr::new_static("createdAt"),
445 LexObjectProperty::String(LexString {
446 format: Some(LexStringFormat::Datetime),
447 ..Default::default()
448 }),
449 );
450 map.insert(
451 SmolStr::new_static("parent"),
452 LexObjectProperty::String(LexString {
453 description: Some(
454 CowStr::new_static(
455 "Optional reference to parent comment for threading",
456 ),
457 ),
458 format: Some(LexStringFormat::AtUri),
459 ..Default::default()
460 }),
461 );
462 map
463 },
464 ..Default::default()
465 }),
466 ..Default::default()
467 }),
468 );
469 map
470 },
471 ..Default::default()
472 }
473}