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, Did, Handle};
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::net_anisota::observatory::layout;
28#[allow(unused_imports)]
29use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
30use serde::{Deserialize, Serialize};
31#[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 CreatedBy<S: BosStr = DefaultStr> {
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub did: Option<Did<S>>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub handle: Option<Handle<S>>,
43 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
44 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
45}
46
47#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
50#[serde(
51 rename_all = "camelCase",
52 bound(deserialize = "S: Deserialize<'de> + BosStr")
53)]
54pub struct Layout<S: BosStr = DefaultStr> {
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub buttons: Option<Data<S>>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub patterns_indicator: Option<Data<S>>,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub shuffle_layout: Option<bool>,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub tile_order: Option<Vec<S>>,
67 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
68 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
69}
70
71#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
74#[serde(
75 rename_all = "camelCase",
76 rename = "net.anisota.observatory.layout",
77 tag = "$type",
78 bound(deserialize = "S: Deserialize<'de> + BosStr")
79)]
80pub struct LayoutRecord<S: BosStr = DefaultStr> {
81 pub created_at: Datetime,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub created_by: Option<layout::CreatedBy<S>>,
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub description: Option<S>,
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub elements: Option<Vec<Data<S>>>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub layout: Option<layout::Layout<S>>,
93 pub name: S,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub schedule: Option<layout::Schedule<S>>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub source: Option<layout::Source<S>>,
99 pub updated_at: Datetime,
101 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
102 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
103}
104
105#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
108#[serde(rename_all = "camelCase")]
109pub struct LayoutRecordGetRecordOutput<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: LayoutRecord<S>,
114}
115
116#[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 Schedule<S: BosStr = DefaultStr> {
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub days_of_week: Option<Vec<i64>>,
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub enabled: Option<bool>,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub end_time: Option<S>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub start_time: Option<S>,
136 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
137 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
138}
139
140#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
143#[serde(
144 rename_all = "camelCase",
145 bound(deserialize = "S: Deserialize<'de> + BosStr")
146)]
147pub struct Source<S: BosStr = DefaultStr> {
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub original_did: Option<Did<S>>,
151 #[serde(skip_serializing_if = "Option::is_none")]
153 pub original_uri: Option<AtUri<S>>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub r#type: Option<SourceType<S>>,
156 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
157 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Hash)]
161pub enum SourceType<S: BosStr = DefaultStr> {
162 Original,
163 Learned,
164 Other(S),
165}
166
167impl<S: BosStr> SourceType<S> {
168 pub fn as_str(&self) -> &str {
169 match self {
170 Self::Original => "original",
171 Self::Learned => "learned",
172 Self::Other(s) => s.as_ref(),
173 }
174 }
175 pub fn from_value(s: S) -> Self {
177 match s.as_ref() {
178 "original" => Self::Original,
179 "learned" => Self::Learned,
180 _ => Self::Other(s),
181 }
182 }
183}
184
185impl<S: BosStr> core::fmt::Display for SourceType<S> {
186 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187 write!(f, "{}", self.as_str())
188 }
189}
190
191impl<S: BosStr> AsRef<str> for SourceType<S> {
192 fn as_ref(&self) -> &str {
193 self.as_str()
194 }
195}
196
197impl<S: BosStr> Serialize for SourceType<S> {
198 fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>
199 where
200 Ser: serde::Serializer,
201 {
202 serializer.serialize_str(self.as_str())
203 }
204}
205
206impl<'de, S: Deserialize<'de> + BosStr> Deserialize<'de> for SourceType<S> {
207 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
208 where
209 D: serde::Deserializer<'de>,
210 {
211 let s = S::deserialize(deserializer)?;
212 Ok(Self::from_value(s))
213 }
214}
215
216impl<S: BosStr + Default> Default for SourceType<S> {
217 fn default() -> Self {
218 Self::Other(Default::default())
219 }
220}
221
222impl<S: BosStr> jacquard_common::IntoStatic for SourceType<S>
223where
224 S: BosStr + jacquard_common::IntoStatic,
225 S::Output: BosStr,
226{
227 type Output = SourceType<S::Output>;
228 fn into_static(self) -> Self::Output {
229 match self {
230 SourceType::Original => SourceType::Original,
231 SourceType::Learned => SourceType::Learned,
232 SourceType::Other(v) => SourceType::Other(v.into_static()),
233 }
234 }
235}
236
237impl<S: BosStr> LayoutRecord<S> {
238 pub fn uri(uri: S) -> Result<RecordUri<S, LayoutRecordRecord>, UriError> {
239 RecordUri::try_from_uri(AtUri::new(uri)?)
240 }
241}
242
243impl<S: BosStr> LexiconSchema for CreatedBy<S> {
244 fn nsid() -> &'static str {
245 "net.anisota.observatory.layout"
246 }
247 fn def_name() -> &'static str {
248 "createdBy"
249 }
250 fn lexicon_doc() -> LexiconDoc<'static> {
251 lexicon_doc_net_anisota_observatory_layout()
252 }
253 fn validate(&self) -> Result<(), ConstraintError> {
254 Ok(())
255 }
256}
257
258impl<S: BosStr> LexiconSchema for Layout<S> {
259 fn nsid() -> &'static str {
260 "net.anisota.observatory.layout"
261 }
262 fn def_name() -> &'static str {
263 "layout"
264 }
265 fn lexicon_doc() -> LexiconDoc<'static> {
266 lexicon_doc_net_anisota_observatory_layout()
267 }
268 fn validate(&self) -> Result<(), ConstraintError> {
269 Ok(())
270 }
271}
272
273#[derive(Debug, Serialize, Deserialize)]
276pub struct LayoutRecordRecord;
277impl XrpcResp for LayoutRecordRecord {
278 const NSID: &'static str = "net.anisota.observatory.layout";
279 const ENCODING: &'static str = "application/json";
280 type Output<S: BosStr> = LayoutRecordGetRecordOutput<S>;
281 type Err = RecordError;
282}
283
284impl<S: BosStr> From<LayoutRecordGetRecordOutput<S>> for LayoutRecord<S> {
285 fn from(output: LayoutRecordGetRecordOutput<S>) -> Self {
286 output.value
287 }
288}
289
290impl<S: BosStr> Collection for LayoutRecord<S> {
291 const NSID: &'static str = "net.anisota.observatory.layout";
292 type Record = LayoutRecordRecord;
293}
294
295impl Collection for LayoutRecordRecord {
296 const NSID: &'static str = "net.anisota.observatory.layout";
297 type Record = LayoutRecordRecord;
298}
299
300impl<S: BosStr> LexiconSchema for LayoutRecord<S> {
301 fn nsid() -> &'static str {
302 "net.anisota.observatory.layout"
303 }
304 fn def_name() -> &'static str {
305 "main"
306 }
307 fn lexicon_doc() -> LexiconDoc<'static> {
308 lexicon_doc_net_anisota_observatory_layout()
309 }
310 fn validate(&self) -> Result<(), ConstraintError> {
311 if let Some(ref value) = self.description {
312 #[allow(unused_comparisons)]
313 if <str>::len(value.as_ref()) > 500usize {
314 return Err(ConstraintError::MaxLength {
315 path: ValidationPath::from_field("description"),
316 max: 500usize,
317 actual: <str>::len(value.as_ref()),
318 });
319 }
320 }
321 {
322 let value = &self.name;
323 #[allow(unused_comparisons)]
324 if <str>::len(value.as_ref()) > 80usize {
325 return Err(ConstraintError::MaxLength {
326 path: ValidationPath::from_field("name"),
327 max: 80usize,
328 actual: <str>::len(value.as_ref()),
329 });
330 }
331 }
332 Ok(())
333 }
334}
335
336impl<S: BosStr> LexiconSchema for Schedule<S> {
337 fn nsid() -> &'static str {
338 "net.anisota.observatory.layout"
339 }
340 fn def_name() -> &'static str {
341 "schedule"
342 }
343 fn lexicon_doc() -> LexiconDoc<'static> {
344 lexicon_doc_net_anisota_observatory_layout()
345 }
346 fn validate(&self) -> Result<(), ConstraintError> {
347 if let Some(ref value) = self.days_of_week {
348 #[allow(unused_comparisons)]
349 if value.len() > 7usize {
350 return Err(ConstraintError::MaxLength {
351 path: ValidationPath::from_field("days_of_week"),
352 max: 7usize,
353 actual: value.len(),
354 });
355 }
356 }
357 if let Some(ref value) = self.end_time {
358 #[allow(unused_comparisons)]
359 if <str>::len(value.as_ref()) > 5usize {
360 return Err(ConstraintError::MaxLength {
361 path: ValidationPath::from_field("end_time"),
362 max: 5usize,
363 actual: <str>::len(value.as_ref()),
364 });
365 }
366 }
367 if let Some(ref value) = self.start_time {
368 #[allow(unused_comparisons)]
369 if <str>::len(value.as_ref()) > 5usize {
370 return Err(ConstraintError::MaxLength {
371 path: ValidationPath::from_field("start_time"),
372 max: 5usize,
373 actual: <str>::len(value.as_ref()),
374 });
375 }
376 }
377 Ok(())
378 }
379}
380
381impl<S: BosStr> LexiconSchema for Source<S> {
382 fn nsid() -> &'static str {
383 "net.anisota.observatory.layout"
384 }
385 fn def_name() -> &'static str {
386 "source"
387 }
388 fn lexicon_doc() -> LexiconDoc<'static> {
389 lexicon_doc_net_anisota_observatory_layout()
390 }
391 fn validate(&self) -> Result<(), ConstraintError> {
392 Ok(())
393 }
394}
395
396fn lexicon_doc_net_anisota_observatory_layout() -> LexiconDoc<'static> {
397 use alloc::collections::BTreeMap;
398 #[allow(unused_imports)]
399 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
400 use jacquard_lexicon::lexicon::*;
401 LexiconDoc {
402 lexicon: Lexicon::Lexicon1,
403 id: CowStr::new_static("net.anisota.observatory.layout"),
404 defs: {
405 let mut map = BTreeMap::new();
406 map.insert(
407 SmolStr::new_static("createdBy"),
408 LexUserType::Object(LexObject {
409 description: Some(CowStr::new_static(
410 "Attribution for the original crafter of this layout.",
411 )),
412 properties: {
413 #[allow(unused_mut)]
414 let mut map = BTreeMap::new();
415 map.insert(
416 SmolStr::new_static("did"),
417 LexObjectProperty::String(LexString {
418 format: Some(LexStringFormat::Did),
419 ..Default::default()
420 }),
421 );
422 map.insert(
423 SmolStr::new_static("handle"),
424 LexObjectProperty::String(LexString {
425 format: Some(LexStringFormat::Handle),
426 ..Default::default()
427 }),
428 );
429 map
430 },
431 ..Default::default()
432 }),
433 );
434 map.insert(
435 SmolStr::new_static("layout"),
436 LexUserType::Object(LexObject {
437 description: Some(
438 CowStr::new_static(
439 "The grid configuration captured by this layout.",
440 ),
441 ),
442 properties: {
443 #[allow(unused_mut)]
444 let mut map = BTreeMap::new();
445 map.insert(
446 SmolStr::new_static("buttons"),
447 LexObjectProperty::Unknown(LexUnknown {
448 ..Default::default()
449 }),
450 );
451 map.insert(
452 SmolStr::new_static("patternsIndicator"),
453 LexObjectProperty::Unknown(LexUnknown {
454 ..Default::default()
455 }),
456 );
457 map.insert(
458 SmolStr::new_static("shuffleLayout"),
459 LexObjectProperty::Boolean(LexBoolean {
460 ..Default::default()
461 }),
462 );
463 map.insert(
464 SmolStr::new_static("tileOrder"),
465 LexObjectProperty::Array(LexArray {
466 description: Some(
467 CowStr::new_static(
468 "Unified rendering order. Entries are 'builtin:<key>' or 'element:<index>' into the record's elements array.",
469 ),
470 ),
471 items: LexArrayItem::String(LexString {
472 max_length: Some(64usize),
473 ..Default::default()
474 }),
475 ..Default::default()
476 }),
477 );
478 map
479 },
480 ..Default::default()
481 }),
482 );
483 map.insert(
484 SmolStr::new_static("main"),
485 LexUserType::Record(LexRecord {
486 description: Some(
487 CowStr::new_static(
488 "A saved Observatory grid layout. Each record is a complete, self-contained snapshot of a layout — built-in button configuration, unified tile order, and embedded element snapshots — so it can be shared by URL and saved ('learned') into another user's PDS without depending on the original author's element records, mirroring the spell architecture. tileOrder entries are 'builtin:<key>' for built-in tiles or 'element:<index>' pointing into the embedded elements array. An optional schedule makes the layout activate automatically during a daily time window.",
489 ),
490 ),
491 key: Some(CowStr::new_static("any")),
492 record: LexRecordRecord::Object(LexObject {
493 required: Some(
494 vec![
495 SmolStr::new_static("name"),
496 SmolStr::new_static("createdAt"),
497 SmolStr::new_static("updatedAt")
498 ],
499 ),
500 properties: {
501 #[allow(unused_mut)]
502 let mut map = BTreeMap::new();
503 map.insert(
504 SmolStr::new_static("createdAt"),
505 LexObjectProperty::String(LexString {
506 description: Some(
507 CowStr::new_static("When this layout was first saved"),
508 ),
509 format: Some(LexStringFormat::Datetime),
510 ..Default::default()
511 }),
512 );
513 map.insert(
514 SmolStr::new_static("createdBy"),
515 LexObjectProperty::Ref(LexRef {
516 r#ref: CowStr::new_static("#createdBy"),
517 ..Default::default()
518 }),
519 );
520 map.insert(
521 SmolStr::new_static("description"),
522 LexObjectProperty::String(LexString {
523 description: Some(
524 CowStr::new_static(
525 "Optional description of what this layout is for",
526 ),
527 ),
528 max_length: Some(500usize),
529 ..Default::default()
530 }),
531 );
532 map.insert(
533 SmolStr::new_static("elements"),
534 LexObjectProperty::Array(LexArray {
535 description: Some(
536 CowStr::new_static(
537 "Embedded snapshots of the custom elements this layout uses. Each entry mirrors the shape of a net.anisota.observatory.element record body (type, name, description, plus the type-specific payload: button, note, quote, reminder, divider, spacer, heading, or widget).",
538 ),
539 ),
540 items: LexArrayItem::Unknown(LexUnknown {
541 ..Default::default()
542 }),
543 ..Default::default()
544 }),
545 );
546 map.insert(
547 SmolStr::new_static("layout"),
548 LexObjectProperty::Ref(LexRef {
549 r#ref: CowStr::new_static("#layout"),
550 ..Default::default()
551 }),
552 );
553 map.insert(
554 SmolStr::new_static("name"),
555 LexObjectProperty::String(LexString {
556 description: Some(
557 CowStr::new_static("Display name for this layout"),
558 ),
559 max_length: Some(80usize),
560 ..Default::default()
561 }),
562 );
563 map.insert(
564 SmolStr::new_static("schedule"),
565 LexObjectProperty::Ref(LexRef {
566 r#ref: CowStr::new_static("#schedule"),
567 ..Default::default()
568 }),
569 );
570 map.insert(
571 SmolStr::new_static("source"),
572 LexObjectProperty::Ref(LexRef {
573 r#ref: CowStr::new_static("#source"),
574 ..Default::default()
575 }),
576 );
577 map.insert(
578 SmolStr::new_static("updatedAt"),
579 LexObjectProperty::String(LexString {
580 description: Some(
581 CowStr::new_static("When this layout was last modified"),
582 ),
583 format: Some(LexStringFormat::Datetime),
584 ..Default::default()
585 }),
586 );
587 map
588 },
589 ..Default::default()
590 }),
591 ..Default::default()
592 }),
593 );
594 map.insert(
595 SmolStr::new_static("schedule"),
596 LexUserType::Object(LexObject {
597 description: Some(
598 CowStr::new_static(
599 "Optional daily activation window. When enabled, the layout takes over the Observatory between startTime and endTime (wrapping past midnight when startTime > endTime), optionally restricted to certain days of the week.",
600 ),
601 ),
602 properties: {
603 #[allow(unused_mut)]
604 let mut map = BTreeMap::new();
605 map.insert(
606 SmolStr::new_static("daysOfWeek"),
607 LexObjectProperty::Array(LexArray {
608 description: Some(
609 CowStr::new_static(
610 "Days the window applies to (0 = Sunday … 6 = Saturday). Empty or absent means every day.",
611 ),
612 ),
613 items: LexArrayItem::Integer(LexInteger {
614 ..Default::default()
615 }),
616 max_length: Some(7usize),
617 ..Default::default()
618 }),
619 );
620 map.insert(
621 SmolStr::new_static("enabled"),
622 LexObjectProperty::Boolean(LexBoolean {
623 ..Default::default()
624 }),
625 );
626 map.insert(
627 SmolStr::new_static("endTime"),
628 LexObjectProperty::String(LexString {
629 description: Some(
630 CowStr::new_static(
631 "Window end as 'HH:MM' (24-hour, local time)",
632 ),
633 ),
634 max_length: Some(5usize),
635 ..Default::default()
636 }),
637 );
638 map.insert(
639 SmolStr::new_static("startTime"),
640 LexObjectProperty::String(LexString {
641 description: Some(
642 CowStr::new_static(
643 "Window start as 'HH:MM' (24-hour, local time)",
644 ),
645 ),
646 max_length: Some(5usize),
647 ..Default::default()
648 }),
649 );
650 map
651 },
652 ..Default::default()
653 }),
654 );
655 map.insert(
656 SmolStr::new_static("source"),
657 LexUserType::Object(LexObject {
658 description: Some(CowStr::new_static(
659 "Provenance backlink for layouts learned from another user.",
660 )),
661 properties: {
662 #[allow(unused_mut)]
663 let mut map = BTreeMap::new();
664 map.insert(
665 SmolStr::new_static("originalDid"),
666 LexObjectProperty::String(LexString {
667 description: Some(CowStr::new_static(
668 "DID of the user this layout was learned from",
669 )),
670 format: Some(LexStringFormat::Did),
671 ..Default::default()
672 }),
673 );
674 map.insert(
675 SmolStr::new_static("originalUri"),
676 LexObjectProperty::String(LexString {
677 description: Some(CowStr::new_static(
678 "AT URI of the record this layout was learned from",
679 )),
680 format: Some(LexStringFormat::AtUri),
681 ..Default::default()
682 }),
683 );
684 map.insert(
685 SmolStr::new_static("type"),
686 LexObjectProperty::String(LexString {
687 ..Default::default()
688 }),
689 );
690 map
691 },
692 ..Default::default()
693 }),
694 );
695 map
696 },
697 ..Default::default()
698 }
699}
700
701pub mod layout_record_state {
702
703 pub use crate::builder_types::{IsSet, IsUnset, Set, Unset};
704 #[allow(unused)]
705 use ::core::marker::PhantomData;
706 mod sealed {
707 pub trait Sealed {}
708 }
709 pub trait State: sealed::Sealed {
711 type CreatedAt;
712 type Name;
713 type UpdatedAt;
714 }
715 pub struct Empty(());
717 impl sealed::Sealed for Empty {}
718 impl State for Empty {
719 type CreatedAt = Unset;
720 type Name = Unset;
721 type UpdatedAt = Unset;
722 }
723 pub struct SetCreatedAt<St: State = Empty>(PhantomData<fn() -> St>);
725 impl<St: State> sealed::Sealed for SetCreatedAt<St> {}
726 impl<St: State> State for SetCreatedAt<St> {
727 type CreatedAt = Set<members::created_at>;
728 type Name = St::Name;
729 type UpdatedAt = St::UpdatedAt;
730 }
731 pub struct SetName<St: State = Empty>(PhantomData<fn() -> St>);
733 impl<St: State> sealed::Sealed for SetName<St> {}
734 impl<St: State> State for SetName<St> {
735 type CreatedAt = St::CreatedAt;
736 type Name = Set<members::name>;
737 type UpdatedAt = St::UpdatedAt;
738 }
739 pub struct SetUpdatedAt<St: State = Empty>(PhantomData<fn() -> St>);
741 impl<St: State> sealed::Sealed for SetUpdatedAt<St> {}
742 impl<St: State> State for SetUpdatedAt<St> {
743 type CreatedAt = St::CreatedAt;
744 type Name = St::Name;
745 type UpdatedAt = Set<members::updated_at>;
746 }
747 #[allow(non_camel_case_types)]
749 pub mod members {
750 pub struct created_at(());
752 pub struct name(());
754 pub struct updated_at(());
756 }
757}
758
759pub struct LayoutRecordBuilder<St: layout_record_state::State, S: BosStr = DefaultStr> {
761 _state: PhantomData<fn() -> St>,
762 _fields: (
763 Option<Datetime>,
764 Option<layout::CreatedBy<S>>,
765 Option<S>,
766 Option<Vec<Data<S>>>,
767 Option<layout::Layout<S>>,
768 Option<S>,
769 Option<layout::Schedule<S>>,
770 Option<layout::Source<S>>,
771 Option<Datetime>,
772 ),
773 _type: PhantomData<fn() -> S>,
774}
775
776impl LayoutRecord<DefaultStr> {
777 pub fn new() -> LayoutRecordBuilder<layout_record_state::Empty, DefaultStr> {
779 LayoutRecordBuilder::new()
780 }
781}
782
783impl<S: BosStr> LayoutRecord<S> {
784 pub fn builder() -> LayoutRecordBuilder<layout_record_state::Empty, S> {
786 LayoutRecordBuilder::builder()
787 }
788}
789
790impl LayoutRecordBuilder<layout_record_state::Empty, DefaultStr> {
791 pub fn new() -> Self {
793 LayoutRecordBuilder {
794 _state: PhantomData,
795 _fields: (None, None, None, None, None, None, None, None, None),
796 _type: PhantomData,
797 }
798 }
799}
800
801impl<S: BosStr> LayoutRecordBuilder<layout_record_state::Empty, S> {
802 pub fn builder() -> Self {
804 LayoutRecordBuilder {
805 _state: PhantomData,
806 _fields: (None, None, None, None, None, None, None, None, None),
807 _type: PhantomData,
808 }
809 }
810}
811
812impl<St, S: BosStr> LayoutRecordBuilder<St, S>
813where
814 St: layout_record_state::State,
815 St::CreatedAt: layout_record_state::IsUnset,
816{
817 pub fn created_at(
819 mut self,
820 value: impl Into<Datetime>,
821 ) -> LayoutRecordBuilder<layout_record_state::SetCreatedAt<St>, S> {
822 self._fields.0 = Option::Some(value.into());
823 LayoutRecordBuilder {
824 _state: PhantomData,
825 _fields: self._fields,
826 _type: PhantomData,
827 }
828 }
829}
830
831impl<St: layout_record_state::State, S: BosStr> LayoutRecordBuilder<St, S> {
832 pub fn created_by(mut self, value: impl Into<Option<layout::CreatedBy<S>>>) -> Self {
834 self._fields.1 = value.into();
835 self
836 }
837 pub fn maybe_created_by(mut self, value: Option<layout::CreatedBy<S>>) -> Self {
839 self._fields.1 = value;
840 self
841 }
842}
843
844impl<St: layout_record_state::State, S: BosStr> LayoutRecordBuilder<St, S> {
845 pub fn description(mut self, value: impl Into<Option<S>>) -> Self {
847 self._fields.2 = value.into();
848 self
849 }
850 pub fn maybe_description(mut self, value: Option<S>) -> Self {
852 self._fields.2 = value;
853 self
854 }
855}
856
857impl<St: layout_record_state::State, S: BosStr> LayoutRecordBuilder<St, S> {
858 pub fn elements(mut self, value: impl Into<Option<Vec<Data<S>>>>) -> Self {
860 self._fields.3 = value.into();
861 self
862 }
863 pub fn maybe_elements(mut self, value: Option<Vec<Data<S>>>) -> Self {
865 self._fields.3 = value;
866 self
867 }
868}
869
870impl<St: layout_record_state::State, S: BosStr> LayoutRecordBuilder<St, S> {
871 pub fn layout(mut self, value: impl Into<Option<layout::Layout<S>>>) -> Self {
873 self._fields.4 = value.into();
874 self
875 }
876 pub fn maybe_layout(mut self, value: Option<layout::Layout<S>>) -> Self {
878 self._fields.4 = value;
879 self
880 }
881}
882
883impl<St, S: BosStr> LayoutRecordBuilder<St, S>
884where
885 St: layout_record_state::State,
886 St::Name: layout_record_state::IsUnset,
887{
888 pub fn name(
890 mut self,
891 value: impl Into<S>,
892 ) -> LayoutRecordBuilder<layout_record_state::SetName<St>, S> {
893 self._fields.5 = Option::Some(value.into());
894 LayoutRecordBuilder {
895 _state: PhantomData,
896 _fields: self._fields,
897 _type: PhantomData,
898 }
899 }
900}
901
902impl<St: layout_record_state::State, S: BosStr> LayoutRecordBuilder<St, S> {
903 pub fn schedule(mut self, value: impl Into<Option<layout::Schedule<S>>>) -> Self {
905 self._fields.6 = value.into();
906 self
907 }
908 pub fn maybe_schedule(mut self, value: Option<layout::Schedule<S>>) -> Self {
910 self._fields.6 = value;
911 self
912 }
913}
914
915impl<St: layout_record_state::State, S: BosStr> LayoutRecordBuilder<St, S> {
916 pub fn source(mut self, value: impl Into<Option<layout::Source<S>>>) -> Self {
918 self._fields.7 = value.into();
919 self
920 }
921 pub fn maybe_source(mut self, value: Option<layout::Source<S>>) -> Self {
923 self._fields.7 = value;
924 self
925 }
926}
927
928impl<St, S: BosStr> LayoutRecordBuilder<St, S>
929where
930 St: layout_record_state::State,
931 St::UpdatedAt: layout_record_state::IsUnset,
932{
933 pub fn updated_at(
935 mut self,
936 value: impl Into<Datetime>,
937 ) -> LayoutRecordBuilder<layout_record_state::SetUpdatedAt<St>, S> {
938 self._fields.8 = Option::Some(value.into());
939 LayoutRecordBuilder {
940 _state: PhantomData,
941 _fields: self._fields,
942 _type: PhantomData,
943 }
944 }
945}
946
947impl<St, S: BosStr> LayoutRecordBuilder<St, S>
948where
949 St: layout_record_state::State,
950 St::CreatedAt: layout_record_state::IsSet,
951 St::Name: layout_record_state::IsSet,
952 St::UpdatedAt: layout_record_state::IsSet,
953{
954 pub fn build(self) -> LayoutRecord<S> {
956 LayoutRecord {
957 created_at: self._fields.0.unwrap(),
958 created_by: self._fields.1,
959 description: self._fields.2,
960 elements: self._fields.3,
961 layout: self._fields.4,
962 name: self._fields.5.unwrap(),
963 schedule: self._fields.6,
964 source: self._fields.7,
965 updated_at: self._fields.8.unwrap(),
966 extra_data: Default::default(),
967 }
968 }
969 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> LayoutRecord<S> {
971 LayoutRecord {
972 created_at: self._fields.0.unwrap(),
973 created_by: self._fields.1,
974 description: self._fields.2,
975 elements: self._fields.3,
976 layout: self._fields.4,
977 name: self._fields.5.unwrap(),
978 schedule: self._fields.6,
979 source: self._fields.7,
980 updated_at: self._fields.8.unwrap(),
981 extra_data: Some(extra_data),
982 }
983 }
984}