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::blob::BlobRef;
19use jacquard_common::types::collection::{Collection, RecordError};
20use jacquard_common::types::string::{AtUri, Cid, Datetime};
21use jacquard_common::types::uri::{RecordUri, UriError};
22use jacquard_common::types::value::Data;
23use jacquard_common::xrpc::XrpcResp;
24use jacquard_derive::{IntoStatic, lexicon, open_union};
25use jacquard_lexicon::lexicon::LexiconDoc;
26use jacquard_lexicon::schema::LexiconSchema;
27
28#[allow(unused_imports)]
29use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
30use serde::{Serialize, Deserialize};
31use crate::network_slices::tools::richtext::facet::Facet;
32use crate::network_slices::tools::document;
33#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
36#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
37pub struct CodeBlock<S: BosStr = DefaultStr> {
38 pub code: S,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub lang: Option<S>,
41 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
42 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
43}
44
45#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
48#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
49pub struct Heading<S: BosStr = DefaultStr> {
50 #[serde(skip_serializing_if = "Option::is_none")]
51 pub facets: Option<Vec<Facet<S>>>,
52 pub level: i64,
53 pub text: S,
54 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
55 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
56}
57
58#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
61#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
62pub struct ImageEmbed<S: BosStr = DefaultStr> {
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub alt: Option<S>,
66 pub image: BlobRef<S>,
67 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
68 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
69}
70
71
72#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
73#[serde(
74 rename_all = "camelCase",
75 rename = "network.slices.tools.document",
76 tag = "$type",
77 bound(deserialize = "S: Deserialize<'de> + BosStr")
78)]
79pub struct Document<S: BosStr = DefaultStr> {
80 pub blocks: Vec<DocumentBlocksItem<S>>,
82 pub created_at: Datetime,
83 pub slug: S,
85 pub title: S,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub updated_at: Option<Datetime>,
89 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
90 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
91}
92
93
94#[open_union]
95#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
96#[serde(tag = "$type", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
97pub enum DocumentBlocksItem<S: BosStr = DefaultStr> {
98 #[serde(rename = "network.slices.tools.document#paragraph")]
99 Paragraph(Box<document::Paragraph<S>>),
100 #[serde(rename = "network.slices.tools.document#heading")]
101 Heading(Box<document::Heading<S>>),
102 #[serde(rename = "network.slices.tools.document#codeBlock")]
103 CodeBlock(Box<document::CodeBlock<S>>),
104 #[serde(rename = "network.slices.tools.document#quote")]
105 Quote(Box<document::Quote<S>>),
106 #[serde(rename = "network.slices.tools.document#tangledEmbed")]
107 TangledEmbed(Box<document::TangledEmbed<S>>),
108 #[serde(rename = "network.slices.tools.document#imageEmbed")]
109 ImageEmbed(Box<document::ImageEmbed<S>>),
110}
111
112#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
115#[serde(rename_all = "camelCase")]
116pub struct DocumentGetRecordOutput<S: BosStr = DefaultStr> {
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub cid: Option<Cid<S>>,
119 pub uri: AtUri<S>,
120 pub value: Document<S>,
121}
122
123#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
126#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
127pub struct Paragraph<S: BosStr = DefaultStr> {
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub facets: Option<Vec<Facet<S>>>,
130 pub text: S,
131 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
132 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
133}
134
135#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
138#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
139pub struct Quote<S: BosStr = DefaultStr> {
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub facets: Option<Vec<Facet<S>>>,
142 pub text: S,
143 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
144 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
145}
146
147#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
150#[serde(rename_all = "camelCase", bound(deserialize = "S: Deserialize<'de> + BosStr"))]
151pub struct TangledEmbed<S: BosStr = DefaultStr> {
152 pub handle: S,
154 pub repo: S,
156 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
157 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
158}
159
160impl<S: BosStr> Document<S> {
161 pub fn uri(uri: S) -> Result<RecordUri<S, DocumentRecord>, UriError> {
162 RecordUri::try_from_uri(AtUri::new(uri)?)
163 }
164}
165
166impl<S: BosStr> LexiconSchema for CodeBlock<S> {
167 fn nsid() -> &'static str {
168 "network.slices.tools.document"
169 }
170 fn def_name() -> &'static str {
171 "codeBlock"
172 }
173 fn lexicon_doc() -> LexiconDoc<'static> {
174 lexicon_doc_network_slices_tools_document()
175 }
176 fn validate(&self) -> Result<(), ConstraintError> {
177 {
178 let value = &self.code;
179 #[allow(unused_comparisons)]
180 if <str>::len(value.as_ref()) > 20000usize {
181 return Err(ConstraintError::MaxLength {
182 path: ValidationPath::from_field("code"),
183 max: 20000usize,
184 actual: <str>::len(value.as_ref()),
185 });
186 }
187 }
188 if let Some(ref value) = self.lang {
189 #[allow(unused_comparisons)]
190 if <str>::len(value.as_ref()) > 50usize {
191 return Err(ConstraintError::MaxLength {
192 path: ValidationPath::from_field("lang"),
193 max: 50usize,
194 actual: <str>::len(value.as_ref()),
195 });
196 }
197 }
198 Ok(())
199 }
200}
201
202impl<S: BosStr> LexiconSchema for Heading<S> {
203 fn nsid() -> &'static str {
204 "network.slices.tools.document"
205 }
206 fn def_name() -> &'static str {
207 "heading"
208 }
209 fn lexicon_doc() -> LexiconDoc<'static> {
210 lexicon_doc_network_slices_tools_document()
211 }
212 fn validate(&self) -> Result<(), ConstraintError> {
213 {
214 let value = &self.level;
215 if *value > 3i64 {
216 return Err(ConstraintError::Maximum {
217 path: ValidationPath::from_field("level"),
218 max: 3i64,
219 actual: *value,
220 });
221 }
222 }
223 {
224 let value = &self.level;
225 if *value < 1i64 {
226 return Err(ConstraintError::Minimum {
227 path: ValidationPath::from_field("level"),
228 min: 1i64,
229 actual: *value,
230 });
231 }
232 }
233 {
234 let value = &self.text;
235 #[allow(unused_comparisons)]
236 if <str>::len(value.as_ref()) > 300usize {
237 return Err(ConstraintError::MaxLength {
238 path: ValidationPath::from_field("text"),
239 max: 300usize,
240 actual: <str>::len(value.as_ref()),
241 });
242 }
243 }
244 Ok(())
245 }
246}
247
248impl<S: BosStr> LexiconSchema for ImageEmbed<S> {
249 fn nsid() -> &'static str {
250 "network.slices.tools.document"
251 }
252 fn def_name() -> &'static str {
253 "imageEmbed"
254 }
255 fn lexicon_doc() -> LexiconDoc<'static> {
256 lexicon_doc_network_slices_tools_document()
257 }
258 fn validate(&self) -> Result<(), ConstraintError> {
259 if let Some(ref value) = self.alt {
260 #[allow(unused_comparisons)]
261 if <str>::len(value.as_ref()) > 1000usize {
262 return Err(ConstraintError::MaxLength {
263 path: ValidationPath::from_field("alt"),
264 max: 1000usize,
265 actual: <str>::len(value.as_ref()),
266 });
267 }
268 }
269 {
270 let value = &self.image;
271 {
272 let size = value.blob().size;
273 if size > 1000000usize {
274 return Err(ConstraintError::BlobTooLarge {
275 path: ValidationPath::from_field("image"),
276 max: 1000000usize,
277 actual: size,
278 });
279 }
280 }
281 }
282 {
283 let value = &self.image;
284 {
285 let mime = value.blob().mime_type.as_str();
286 let accepted: &[&str] = &["image/*"];
287 let matched = accepted
288 .iter()
289 .any(|pattern| {
290 if *pattern == "*/*" {
291 true
292 } else if pattern.ends_with("/*") {
293 let prefix = &pattern[..pattern.len() - 2];
294 mime.starts_with(prefix)
295 && mime.as_bytes().get(prefix.len()) == Some(&b'/')
296 } else {
297 mime == *pattern
298 }
299 });
300 if !matched {
301 return Err(ConstraintError::BlobMimeTypeNotAccepted {
302 path: ValidationPath::from_field("image"),
303 accepted: vec!["image/*".to_string()],
304 actual: mime.to_string(),
305 });
306 }
307 }
308 }
309 Ok(())
310 }
311}
312
313#[derive(Debug, Serialize, Deserialize)]
316pub struct DocumentRecord;
317impl XrpcResp for DocumentRecord {
318 const NSID: &'static str = "network.slices.tools.document";
319 const ENCODING: &'static str = "application/json";
320 type Output<S: BosStr> = DocumentGetRecordOutput<S>;
321 type Err = RecordError;
322}
323
324impl<S: BosStr> From<DocumentGetRecordOutput<S>> for Document<S> {
325 fn from(output: DocumentGetRecordOutput<S>) -> Self {
326 output.value
327 }
328}
329
330impl<S: BosStr> Collection for Document<S> {
331 const NSID: &'static str = "network.slices.tools.document";
332 type Record = DocumentRecord;
333}
334
335impl Collection for DocumentRecord {
336 const NSID: &'static str = "network.slices.tools.document";
337 type Record = DocumentRecord;
338}
339
340impl<S: BosStr> LexiconSchema for Document<S> {
341 fn nsid() -> &'static str {
342 "network.slices.tools.document"
343 }
344 fn def_name() -> &'static str {
345 "main"
346 }
347 fn lexicon_doc() -> LexiconDoc<'static> {
348 lexicon_doc_network_slices_tools_document()
349 }
350 fn validate(&self) -> Result<(), ConstraintError> {
351 {
352 let value = &self.slug;
353 #[allow(unused_comparisons)]
354 if <str>::len(value.as_ref()) > 100usize {
355 return Err(ConstraintError::MaxLength {
356 path: ValidationPath::from_field("slug"),
357 max: 100usize,
358 actual: <str>::len(value.as_ref()),
359 });
360 }
361 }
362 {
363 let value = &self.title;
364 #[allow(unused_comparisons)]
365 if <str>::len(value.as_ref()) > 300usize {
366 return Err(ConstraintError::MaxLength {
367 path: ValidationPath::from_field("title"),
368 max: 300usize,
369 actual: <str>::len(value.as_ref()),
370 });
371 }
372 }
373 Ok(())
374 }
375}
376
377impl<S: BosStr> LexiconSchema for Paragraph<S> {
378 fn nsid() -> &'static str {
379 "network.slices.tools.document"
380 }
381 fn def_name() -> &'static str {
382 "paragraph"
383 }
384 fn lexicon_doc() -> LexiconDoc<'static> {
385 lexicon_doc_network_slices_tools_document()
386 }
387 fn validate(&self) -> Result<(), ConstraintError> {
388 {
389 let value = &self.text;
390 #[allow(unused_comparisons)]
391 if <str>::len(value.as_ref()) > 10000usize {
392 return Err(ConstraintError::MaxLength {
393 path: ValidationPath::from_field("text"),
394 max: 10000usize,
395 actual: <str>::len(value.as_ref()),
396 });
397 }
398 }
399 Ok(())
400 }
401}
402
403impl<S: BosStr> LexiconSchema for Quote<S> {
404 fn nsid() -> &'static str {
405 "network.slices.tools.document"
406 }
407 fn def_name() -> &'static str {
408 "quote"
409 }
410 fn lexicon_doc() -> LexiconDoc<'static> {
411 lexicon_doc_network_slices_tools_document()
412 }
413 fn validate(&self) -> Result<(), ConstraintError> {
414 {
415 let value = &self.text;
416 #[allow(unused_comparisons)]
417 if <str>::len(value.as_ref()) > 5000usize {
418 return Err(ConstraintError::MaxLength {
419 path: ValidationPath::from_field("text"),
420 max: 5000usize,
421 actual: <str>::len(value.as_ref()),
422 });
423 }
424 }
425 Ok(())
426 }
427}
428
429impl<S: BosStr> LexiconSchema for TangledEmbed<S> {
430 fn nsid() -> &'static str {
431 "network.slices.tools.document"
432 }
433 fn def_name() -> &'static str {
434 "tangledEmbed"
435 }
436 fn lexicon_doc() -> LexiconDoc<'static> {
437 lexicon_doc_network_slices_tools_document()
438 }
439 fn validate(&self) -> Result<(), ConstraintError> {
440 {
441 let value = &self.handle;
442 #[allow(unused_comparisons)]
443 if <str>::len(value.as_ref()) > 300usize {
444 return Err(ConstraintError::MaxLength {
445 path: ValidationPath::from_field("handle"),
446 max: 300usize,
447 actual: <str>::len(value.as_ref()),
448 });
449 }
450 }
451 {
452 let value = &self.repo;
453 #[allow(unused_comparisons)]
454 if <str>::len(value.as_ref()) > 300usize {
455 return Err(ConstraintError::MaxLength {
456 path: ValidationPath::from_field("repo"),
457 max: 300usize,
458 actual: <str>::len(value.as_ref()),
459 });
460 }
461 }
462 Ok(())
463 }
464}
465
466fn lexicon_doc_network_slices_tools_document() -> LexiconDoc<'static> {
467 #[allow(unused_imports)]
468 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
469 use jacquard_lexicon::lexicon::*;
470 use alloc::collections::BTreeMap;
471 LexiconDoc {
472 lexicon: Lexicon::Lexicon1,
473 id: CowStr::new_static("network.slices.tools.document"),
474 defs: {
475 let mut map = BTreeMap::new();
476 map.insert(
477 SmolStr::new_static("codeBlock"),
478 LexUserType::Object(LexObject {
479 description: Some(CowStr::new_static("A fenced code block")),
480 required: Some(vec![SmolStr::new_static("code")]),
481 properties: {
482 #[allow(unused_mut)]
483 let mut map = BTreeMap::new();
484 map.insert(
485 SmolStr::new_static("code"),
486 LexObjectProperty::String(LexString {
487 max_length: Some(20000usize),
488 ..Default::default()
489 }),
490 );
491 map.insert(
492 SmolStr::new_static("lang"),
493 LexObjectProperty::String(LexString {
494 max_length: Some(50usize),
495 ..Default::default()
496 }),
497 );
498 map
499 },
500 ..Default::default()
501 }),
502 );
503 map.insert(
504 SmolStr::new_static("heading"),
505 LexUserType::Object(LexObject {
506 description: Some(
507 CowStr::new_static(
508 "A heading block (h1-h3) with optional inline formatting",
509 ),
510 ),
511 required: Some(
512 vec![SmolStr::new_static("level"), SmolStr::new_static("text")],
513 ),
514 properties: {
515 #[allow(unused_mut)]
516 let mut map = BTreeMap::new();
517 map.insert(
518 SmolStr::new_static("facets"),
519 LexObjectProperty::Array(LexArray {
520 items: LexArrayItem::Ref(LexRef {
521 r#ref: CowStr::new_static(
522 "network.slices.tools.richtext.facet",
523 ),
524 ..Default::default()
525 }),
526 ..Default::default()
527 }),
528 );
529 map.insert(
530 SmolStr::new_static("level"),
531 LexObjectProperty::Integer(LexInteger {
532 minimum: Some(1i64),
533 maximum: Some(3i64),
534 ..Default::default()
535 }),
536 );
537 map.insert(
538 SmolStr::new_static("text"),
539 LexObjectProperty::String(LexString {
540 max_length: Some(300usize),
541 ..Default::default()
542 }),
543 );
544 map
545 },
546 ..Default::default()
547 }),
548 );
549 map.insert(
550 SmolStr::new_static("imageEmbed"),
551 LexUserType::Object(LexObject {
552 description: Some(
553 CowStr::new_static("An embedded image with alt text"),
554 ),
555 required: Some(vec![SmolStr::new_static("image")]),
556 properties: {
557 #[allow(unused_mut)]
558 let mut map = BTreeMap::new();
559 map.insert(
560 SmolStr::new_static("alt"),
561 LexObjectProperty::String(LexString {
562 description: Some(
563 CowStr::new_static("Alt text for accessibility"),
564 ),
565 max_length: Some(1000usize),
566 ..Default::default()
567 }),
568 );
569 map.insert(
570 SmolStr::new_static("image"),
571 LexObjectProperty::Blob(LexBlob { ..Default::default() }),
572 );
573 map
574 },
575 ..Default::default()
576 }),
577 );
578 map.insert(
579 SmolStr::new_static("main"),
580 LexUserType::Record(LexRecord {
581 key: Some(CowStr::new_static("tid")),
582 record: LexRecordRecord::Object(LexObject {
583 required: Some(
584 vec![
585 SmolStr::new_static("title"), SmolStr::new_static("slug"),
586 SmolStr::new_static("blocks"),
587 SmolStr::new_static("createdAt")
588 ],
589 ),
590 properties: {
591 #[allow(unused_mut)]
592 let mut map = BTreeMap::new();
593 map.insert(
594 SmolStr::new_static("blocks"),
595 LexObjectProperty::Array(LexArray {
596 description: Some(
597 CowStr::new_static("Document content as array of blocks"),
598 ),
599 items: LexArrayItem::Union(LexRefUnion {
600 refs: vec![
601 CowStr::new_static("#paragraph"),
602 CowStr::new_static("#heading"),
603 CowStr::new_static("#codeBlock"),
604 CowStr::new_static("#quote"),
605 CowStr::new_static("#tangledEmbed"),
606 CowStr::new_static("#imageEmbed")
607 ],
608 ..Default::default()
609 }),
610 ..Default::default()
611 }),
612 );
613 map.insert(
614 SmolStr::new_static("createdAt"),
615 LexObjectProperty::String(LexString {
616 format: Some(LexStringFormat::Datetime),
617 ..Default::default()
618 }),
619 );
620 map.insert(
621 SmolStr::new_static("slug"),
622 LexObjectProperty::String(LexString {
623 description: Some(
624 CowStr::new_static(
625 "URL-friendly identifier, unique per author",
626 ),
627 ),
628 max_length: Some(100usize),
629 ..Default::default()
630 }),
631 );
632 map.insert(
633 SmolStr::new_static("title"),
634 LexObjectProperty::String(LexString {
635 description: Some(CowStr::new_static("Document title")),
636 max_length: Some(300usize),
637 ..Default::default()
638 }),
639 );
640 map.insert(
641 SmolStr::new_static("updatedAt"),
642 LexObjectProperty::String(LexString {
643 format: Some(LexStringFormat::Datetime),
644 ..Default::default()
645 }),
646 );
647 map
648 },
649 ..Default::default()
650 }),
651 ..Default::default()
652 }),
653 );
654 map.insert(
655 SmolStr::new_static("paragraph"),
656 LexUserType::Object(LexObject {
657 description: Some(
658 CowStr::new_static(
659 "A paragraph block with optional inline formatting",
660 ),
661 ),
662 required: Some(vec![SmolStr::new_static("text")]),
663 properties: {
664 #[allow(unused_mut)]
665 let mut map = BTreeMap::new();
666 map.insert(
667 SmolStr::new_static("facets"),
668 LexObjectProperty::Array(LexArray {
669 items: LexArrayItem::Ref(LexRef {
670 r#ref: CowStr::new_static(
671 "network.slices.tools.richtext.facet",
672 ),
673 ..Default::default()
674 }),
675 ..Default::default()
676 }),
677 );
678 map.insert(
679 SmolStr::new_static("text"),
680 LexObjectProperty::String(LexString {
681 max_length: Some(10000usize),
682 ..Default::default()
683 }),
684 );
685 map
686 },
687 ..Default::default()
688 }),
689 );
690 map.insert(
691 SmolStr::new_static("quote"),
692 LexUserType::Object(LexObject {
693 description: Some(
694 CowStr::new_static(
695 "A blockquote with optional inline formatting",
696 ),
697 ),
698 required: Some(vec![SmolStr::new_static("text")]),
699 properties: {
700 #[allow(unused_mut)]
701 let mut map = BTreeMap::new();
702 map.insert(
703 SmolStr::new_static("facets"),
704 LexObjectProperty::Array(LexArray {
705 items: LexArrayItem::Ref(LexRef {
706 r#ref: CowStr::new_static(
707 "network.slices.tools.richtext.facet",
708 ),
709 ..Default::default()
710 }),
711 ..Default::default()
712 }),
713 );
714 map.insert(
715 SmolStr::new_static("text"),
716 LexObjectProperty::String(LexString {
717 max_length: Some(5000usize),
718 ..Default::default()
719 }),
720 );
721 map
722 },
723 ..Default::default()
724 }),
725 );
726 map.insert(
727 SmolStr::new_static("tangledEmbed"),
728 LexUserType::Object(LexObject {
729 description: Some(
730 CowStr::new_static("An embedded Tangled repo card"),
731 ),
732 required: Some(
733 vec![SmolStr::new_static("handle"), SmolStr::new_static("repo")],
734 ),
735 properties: {
736 #[allow(unused_mut)]
737 let mut map = BTreeMap::new();
738 map.insert(
739 SmolStr::new_static("handle"),
740 LexObjectProperty::String(LexString {
741 description: Some(
742 CowStr::new_static("The repo owner's handle"),
743 ),
744 max_length: Some(300usize),
745 ..Default::default()
746 }),
747 );
748 map.insert(
749 SmolStr::new_static("repo"),
750 LexObjectProperty::String(LexString {
751 description: Some(
752 CowStr::new_static("The repository name"),
753 ),
754 max_length: Some(300usize),
755 ..Default::default()
756 }),
757 );
758 map
759 },
760 ..Default::default()
761 }),
762 );
763 map
764 },
765 ..Default::default()
766 }
767}
768
769pub mod heading_state {
770
771 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
772 #[allow(unused)]
773 use ::core::marker::PhantomData;
774 mod sealed {
775 pub trait Sealed {}
776 }
777 pub trait State: sealed::Sealed {
779 type Level;
780 type Text;
781 }
782 pub struct Empty(());
784 impl sealed::Sealed for Empty {}
785 impl State for Empty {
786 type Level = Unset;
787 type Text = Unset;
788 }
789 pub struct SetLevel<St: State = Empty>(PhantomData<fn() -> St>);
791 impl<St: State> sealed::Sealed for SetLevel<St> {}
792 impl<St: State> State for SetLevel<St> {
793 type Level = Set<members::level>;
794 type Text = St::Text;
795 }
796 pub struct SetText<St: State = Empty>(PhantomData<fn() -> St>);
798 impl<St: State> sealed::Sealed for SetText<St> {}
799 impl<St: State> State for SetText<St> {
800 type Level = St::Level;
801 type Text = Set<members::text>;
802 }
803 #[allow(non_camel_case_types)]
805 pub mod members {
806 pub struct level(());
808 pub struct text(());
810 }
811}
812
813pub struct HeadingBuilder<St: heading_state::State, S: BosStr = DefaultStr> {
815 _state: PhantomData<fn() -> St>,
816 _fields: (Option<Vec<Facet<S>>>, Option<i64>, Option<S>),
817 _type: PhantomData<fn() -> S>,
818}
819
820impl Heading<DefaultStr> {
821 pub fn new() -> HeadingBuilder<heading_state::Empty, DefaultStr> {
823 HeadingBuilder::new()
824 }
825}
826
827impl<S: BosStr> Heading<S> {
828 pub fn builder() -> HeadingBuilder<heading_state::Empty, S> {
830 HeadingBuilder::builder()
831 }
832}
833
834impl HeadingBuilder<heading_state::Empty, DefaultStr> {
835 pub fn new() -> Self {
837 HeadingBuilder {
838 _state: PhantomData,
839 _fields: (None, None, None),
840 _type: PhantomData,
841 }
842 }
843}
844
845impl<S: BosStr> HeadingBuilder<heading_state::Empty, S> {
846 pub fn builder() -> Self {
848 HeadingBuilder {
849 _state: PhantomData,
850 _fields: (None, None, None),
851 _type: PhantomData,
852 }
853 }
854}
855
856impl<St: heading_state::State, S: BosStr> HeadingBuilder<St, S> {
857 pub fn facets(mut self, value: impl Into<Option<Vec<Facet<S>>>>) -> Self {
859 self._fields.0 = value.into();
860 self
861 }
862 pub fn maybe_facets(mut self, value: Option<Vec<Facet<S>>>) -> Self {
864 self._fields.0 = value;
865 self
866 }
867}
868
869impl<St, S: BosStr> HeadingBuilder<St, S>
870where
871 St: heading_state::State,
872 St::Level: heading_state::IsUnset,
873{
874 pub fn level(
876 mut self,
877 value: impl Into<i64>,
878 ) -> HeadingBuilder<heading_state::SetLevel<St>, S> {
879 self._fields.1 = Option::Some(value.into());
880 HeadingBuilder {
881 _state: PhantomData,
882 _fields: self._fields,
883 _type: PhantomData,
884 }
885 }
886}
887
888impl<St, S: BosStr> HeadingBuilder<St, S>
889where
890 St: heading_state::State,
891 St::Text: heading_state::IsUnset,
892{
893 pub fn text(
895 mut self,
896 value: impl Into<S>,
897 ) -> HeadingBuilder<heading_state::SetText<St>, S> {
898 self._fields.2 = Option::Some(value.into());
899 HeadingBuilder {
900 _state: PhantomData,
901 _fields: self._fields,
902 _type: PhantomData,
903 }
904 }
905}
906
907impl<St, S: BosStr> HeadingBuilder<St, S>
908where
909 St: heading_state::State,
910 St::Level: heading_state::IsSet,
911 St::Text: heading_state::IsSet,
912{
913 pub fn build(self) -> Heading<S> {
915 Heading {
916 facets: self._fields.0,
917 level: self._fields.1.unwrap(),
918 text: self._fields.2.unwrap(),
919 extra_data: Default::default(),
920 }
921 }
922 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Heading<S> {
924 Heading {
925 facets: self._fields.0,
926 level: self._fields.1.unwrap(),
927 text: self._fields.2.unwrap(),
928 extra_data: Some(extra_data),
929 }
930 }
931}
932
933pub mod image_embed_state {
934
935 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
936 #[allow(unused)]
937 use ::core::marker::PhantomData;
938 mod sealed {
939 pub trait Sealed {}
940 }
941 pub trait State: sealed::Sealed {
943 type Image;
944 }
945 pub struct Empty(());
947 impl sealed::Sealed for Empty {}
948 impl State for Empty {
949 type Image = Unset;
950 }
951 pub struct SetImage<St: State = Empty>(PhantomData<fn() -> St>);
953 impl<St: State> sealed::Sealed for SetImage<St> {}
954 impl<St: State> State for SetImage<St> {
955 type Image = Set<members::image>;
956 }
957 #[allow(non_camel_case_types)]
959 pub mod members {
960 pub struct image(());
962 }
963}
964
965pub struct ImageEmbedBuilder<St: image_embed_state::State, S: BosStr = DefaultStr> {
967 _state: PhantomData<fn() -> St>,
968 _fields: (Option<S>, Option<BlobRef<S>>),
969 _type: PhantomData<fn() -> S>,
970}
971
972impl ImageEmbed<DefaultStr> {
973 pub fn new() -> ImageEmbedBuilder<image_embed_state::Empty, DefaultStr> {
975 ImageEmbedBuilder::new()
976 }
977}
978
979impl<S: BosStr> ImageEmbed<S> {
980 pub fn builder() -> ImageEmbedBuilder<image_embed_state::Empty, S> {
982 ImageEmbedBuilder::builder()
983 }
984}
985
986impl ImageEmbedBuilder<image_embed_state::Empty, DefaultStr> {
987 pub fn new() -> Self {
989 ImageEmbedBuilder {
990 _state: PhantomData,
991 _fields: (None, None),
992 _type: PhantomData,
993 }
994 }
995}
996
997impl<S: BosStr> ImageEmbedBuilder<image_embed_state::Empty, S> {
998 pub fn builder() -> Self {
1000 ImageEmbedBuilder {
1001 _state: PhantomData,
1002 _fields: (None, None),
1003 _type: PhantomData,
1004 }
1005 }
1006}
1007
1008impl<St: image_embed_state::State, S: BosStr> ImageEmbedBuilder<St, S> {
1009 pub fn alt(mut self, value: impl Into<Option<S>>) -> Self {
1011 self._fields.0 = value.into();
1012 self
1013 }
1014 pub fn maybe_alt(mut self, value: Option<S>) -> Self {
1016 self._fields.0 = value;
1017 self
1018 }
1019}
1020
1021impl<St, S: BosStr> ImageEmbedBuilder<St, S>
1022where
1023 St: image_embed_state::State,
1024 St::Image: image_embed_state::IsUnset,
1025{
1026 pub fn image(
1028 mut self,
1029 value: impl Into<BlobRef<S>>,
1030 ) -> ImageEmbedBuilder<image_embed_state::SetImage<St>, S> {
1031 self._fields.1 = Option::Some(value.into());
1032 ImageEmbedBuilder {
1033 _state: PhantomData,
1034 _fields: self._fields,
1035 _type: PhantomData,
1036 }
1037 }
1038}
1039
1040impl<St, S: BosStr> ImageEmbedBuilder<St, S>
1041where
1042 St: image_embed_state::State,
1043 St::Image: image_embed_state::IsSet,
1044{
1045 pub fn build(self) -> ImageEmbed<S> {
1047 ImageEmbed {
1048 alt: self._fields.0,
1049 image: self._fields.1.unwrap(),
1050 extra_data: Default::default(),
1051 }
1052 }
1053 pub fn build_with_data(
1055 self,
1056 extra_data: BTreeMap<SmolStr, Data<S>>,
1057 ) -> ImageEmbed<S> {
1058 ImageEmbed {
1059 alt: self._fields.0,
1060 image: self._fields.1.unwrap(),
1061 extra_data: Some(extra_data),
1062 }
1063 }
1064}
1065
1066pub mod document_state {
1067
1068 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
1069 #[allow(unused)]
1070 use ::core::marker::PhantomData;
1071 mod sealed {
1072 pub trait Sealed {}
1073 }
1074 pub trait State: sealed::Sealed {
1076 type Blocks;
1077 type CreatedAt;
1078 type Slug;
1079 type Title;
1080 }
1081 pub struct Empty(());
1083 impl sealed::Sealed for Empty {}
1084 impl State for Empty {
1085 type Blocks = Unset;
1086 type CreatedAt = Unset;
1087 type Slug = Unset;
1088 type Title = Unset;
1089 }
1090 pub struct SetBlocks<St: State = Empty>(PhantomData<fn() -> St>);
1092 impl<St: State> sealed::Sealed for SetBlocks<St> {}
1093 impl<St: State> State for SetBlocks<St> {
1094 type Blocks = Set<members::blocks>;
1095 type CreatedAt = St::CreatedAt;
1096 type Slug = St::Slug;
1097 type Title = St::Title;
1098 }
1099 pub struct SetCreatedAt<St: State = Empty>(PhantomData<fn() -> St>);
1101 impl<St: State> sealed::Sealed for SetCreatedAt<St> {}
1102 impl<St: State> State for SetCreatedAt<St> {
1103 type Blocks = St::Blocks;
1104 type CreatedAt = Set<members::created_at>;
1105 type Slug = St::Slug;
1106 type Title = St::Title;
1107 }
1108 pub struct SetSlug<St: State = Empty>(PhantomData<fn() -> St>);
1110 impl<St: State> sealed::Sealed for SetSlug<St> {}
1111 impl<St: State> State for SetSlug<St> {
1112 type Blocks = St::Blocks;
1113 type CreatedAt = St::CreatedAt;
1114 type Slug = Set<members::slug>;
1115 type Title = St::Title;
1116 }
1117 pub struct SetTitle<St: State = Empty>(PhantomData<fn() -> St>);
1119 impl<St: State> sealed::Sealed for SetTitle<St> {}
1120 impl<St: State> State for SetTitle<St> {
1121 type Blocks = St::Blocks;
1122 type CreatedAt = St::CreatedAt;
1123 type Slug = St::Slug;
1124 type Title = Set<members::title>;
1125 }
1126 #[allow(non_camel_case_types)]
1128 pub mod members {
1129 pub struct blocks(());
1131 pub struct created_at(());
1133 pub struct slug(());
1135 pub struct title(());
1137 }
1138}
1139
1140pub struct DocumentBuilder<St: document_state::State, S: BosStr = DefaultStr> {
1142 _state: PhantomData<fn() -> St>,
1143 _fields: (
1144 Option<Vec<DocumentBlocksItem<S>>>,
1145 Option<Datetime>,
1146 Option<S>,
1147 Option<S>,
1148 Option<Datetime>,
1149 ),
1150 _type: PhantomData<fn() -> S>,
1151}
1152
1153impl Document<DefaultStr> {
1154 pub fn new() -> DocumentBuilder<document_state::Empty, DefaultStr> {
1156 DocumentBuilder::new()
1157 }
1158}
1159
1160impl<S: BosStr> Document<S> {
1161 pub fn builder() -> DocumentBuilder<document_state::Empty, S> {
1163 DocumentBuilder::builder()
1164 }
1165}
1166
1167impl DocumentBuilder<document_state::Empty, DefaultStr> {
1168 pub fn new() -> Self {
1170 DocumentBuilder {
1171 _state: PhantomData,
1172 _fields: (None, None, None, None, None),
1173 _type: PhantomData,
1174 }
1175 }
1176}
1177
1178impl<S: BosStr> DocumentBuilder<document_state::Empty, S> {
1179 pub fn builder() -> Self {
1181 DocumentBuilder {
1182 _state: PhantomData,
1183 _fields: (None, None, None, None, None),
1184 _type: PhantomData,
1185 }
1186 }
1187}
1188
1189impl<St, S: BosStr> DocumentBuilder<St, S>
1190where
1191 St: document_state::State,
1192 St::Blocks: document_state::IsUnset,
1193{
1194 pub fn blocks(
1196 mut self,
1197 value: impl Into<Vec<DocumentBlocksItem<S>>>,
1198 ) -> DocumentBuilder<document_state::SetBlocks<St>, S> {
1199 self._fields.0 = Option::Some(value.into());
1200 DocumentBuilder {
1201 _state: PhantomData,
1202 _fields: self._fields,
1203 _type: PhantomData,
1204 }
1205 }
1206}
1207
1208impl<St, S: BosStr> DocumentBuilder<St, S>
1209where
1210 St: document_state::State,
1211 St::CreatedAt: document_state::IsUnset,
1212{
1213 pub fn created_at(
1215 mut self,
1216 value: impl Into<Datetime>,
1217 ) -> DocumentBuilder<document_state::SetCreatedAt<St>, S> {
1218 self._fields.1 = Option::Some(value.into());
1219 DocumentBuilder {
1220 _state: PhantomData,
1221 _fields: self._fields,
1222 _type: PhantomData,
1223 }
1224 }
1225}
1226
1227impl<St, S: BosStr> DocumentBuilder<St, S>
1228where
1229 St: document_state::State,
1230 St::Slug: document_state::IsUnset,
1231{
1232 pub fn slug(
1234 mut self,
1235 value: impl Into<S>,
1236 ) -> DocumentBuilder<document_state::SetSlug<St>, S> {
1237 self._fields.2 = Option::Some(value.into());
1238 DocumentBuilder {
1239 _state: PhantomData,
1240 _fields: self._fields,
1241 _type: PhantomData,
1242 }
1243 }
1244}
1245
1246impl<St, S: BosStr> DocumentBuilder<St, S>
1247where
1248 St: document_state::State,
1249 St::Title: document_state::IsUnset,
1250{
1251 pub fn title(
1253 mut self,
1254 value: impl Into<S>,
1255 ) -> DocumentBuilder<document_state::SetTitle<St>, S> {
1256 self._fields.3 = Option::Some(value.into());
1257 DocumentBuilder {
1258 _state: PhantomData,
1259 _fields: self._fields,
1260 _type: PhantomData,
1261 }
1262 }
1263}
1264
1265impl<St: document_state::State, S: BosStr> DocumentBuilder<St, S> {
1266 pub fn updated_at(mut self, value: impl Into<Option<Datetime>>) -> Self {
1268 self._fields.4 = value.into();
1269 self
1270 }
1271 pub fn maybe_updated_at(mut self, value: Option<Datetime>) -> Self {
1273 self._fields.4 = value;
1274 self
1275 }
1276}
1277
1278impl<St, S: BosStr> DocumentBuilder<St, S>
1279where
1280 St: document_state::State,
1281 St::Blocks: document_state::IsSet,
1282 St::CreatedAt: document_state::IsSet,
1283 St::Slug: document_state::IsSet,
1284 St::Title: document_state::IsSet,
1285{
1286 pub fn build(self) -> Document<S> {
1288 Document {
1289 blocks: self._fields.0.unwrap(),
1290 created_at: self._fields.1.unwrap(),
1291 slug: self._fields.2.unwrap(),
1292 title: self._fields.3.unwrap(),
1293 updated_at: self._fields.4,
1294 extra_data: Default::default(),
1295 }
1296 }
1297 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Document<S> {
1299 Document {
1300 blocks: self._fields.0.unwrap(),
1301 created_at: self._fields.1.unwrap(),
1302 slug: self._fields.2.unwrap(),
1303 title: self._fields.3.unwrap(),
1304 updated_at: self._fields.4,
1305 extra_data: Some(extra_data),
1306 }
1307 }
1308}