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::net_anisota::chronicle::progress;
28#[allow(unused_imports)]
29use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
30use serde::{Deserialize, Serialize};
31#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
34#[serde(
35 rename_all = "camelCase",
36 bound(deserialize = "S: Deserialize<'de> + BosStr")
37)]
38pub struct ChronicleSignature<S: BosStr = DefaultStr> {
39 pub alg: S,
41 pub kid: S,
43 pub nonce: S,
45 pub sig: S,
47 pub signed_at: Datetime,
49 pub version: i64,
51 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
52 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
53}
54
55#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
58#[serde(
59 rename_all = "camelCase",
60 rename = "net.anisota.chronicle.progress",
61 tag = "$type",
62 bound(deserialize = "S: Deserialize<'de> + BosStr")
63)]
64pub struct Progress<S: BosStr = DefaultStr> {
65 pub created_at: Datetime,
67 pub level: i64,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub progress_percentage: Option<S>,
72 pub signature: progress::ChronicleSignature<S>,
73 pub total_xp: i64,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub trigger_source: Option<S>,
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub updated_at: Option<Datetime>,
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub xp_gained_since_last_sign: Option<i64>,
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub xp_to_next_level: Option<i64>,
87 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
88 pub extra_data: Option<BTreeMap<SmolStr, Data<S>>>,
89}
90
91#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
94#[serde(rename_all = "camelCase")]
95pub struct ProgressGetRecordOutput<S: BosStr = DefaultStr> {
96 #[serde(skip_serializing_if = "Option::is_none")]
97 pub cid: Option<Cid<S>>,
98 pub uri: AtUri<S>,
99 pub value: Progress<S>,
100}
101
102impl<S: BosStr> Progress<S> {
103 pub fn uri(uri: S) -> Result<RecordUri<S, ProgressRecord>, UriError> {
104 RecordUri::try_from_uri(AtUri::new(uri)?)
105 }
106}
107
108impl<S: BosStr> LexiconSchema for ChronicleSignature<S> {
109 fn nsid() -> &'static str {
110 "net.anisota.chronicle.progress"
111 }
112 fn def_name() -> &'static str {
113 "chronicleSignature"
114 }
115 fn lexicon_doc() -> LexiconDoc<'static> {
116 lexicon_doc_net_anisota_chronicle_progress()
117 }
118 fn validate(&self) -> Result<(), ConstraintError> {
119 Ok(())
120 }
121}
122
123#[derive(Debug, Serialize, Deserialize)]
126pub struct ProgressRecord;
127impl XrpcResp for ProgressRecord {
128 const NSID: &'static str = "net.anisota.chronicle.progress";
129 const ENCODING: &'static str = "application/json";
130 type Output<S: BosStr> = ProgressGetRecordOutput<S>;
131 type Err = RecordError;
132}
133
134impl<S: BosStr> From<ProgressGetRecordOutput<S>> for Progress<S> {
135 fn from(output: ProgressGetRecordOutput<S>) -> Self {
136 output.value
137 }
138}
139
140impl<S: BosStr> Collection for Progress<S> {
141 const NSID: &'static str = "net.anisota.chronicle.progress";
142 type Record = ProgressRecord;
143}
144
145impl Collection for ProgressRecord {
146 const NSID: &'static str = "net.anisota.chronicle.progress";
147 type Record = ProgressRecord;
148}
149
150impl<S: BosStr> LexiconSchema for Progress<S> {
151 fn nsid() -> &'static str {
152 "net.anisota.chronicle.progress"
153 }
154 fn def_name() -> &'static str {
155 "main"
156 }
157 fn lexicon_doc() -> LexiconDoc<'static> {
158 lexicon_doc_net_anisota_chronicle_progress()
159 }
160 fn validate(&self) -> Result<(), ConstraintError> {
161 {
162 let value = &self.level;
163 if *value > 99i64 {
164 return Err(ConstraintError::Maximum {
165 path: ValidationPath::from_field("level"),
166 max: 99i64,
167 actual: *value,
168 });
169 }
170 }
171 {
172 let value = &self.level;
173 if *value < 1i64 {
174 return Err(ConstraintError::Minimum {
175 path: ValidationPath::from_field("level"),
176 min: 1i64,
177 actual: *value,
178 });
179 }
180 }
181 {
182 let value = &self.total_xp;
183 if *value < 0i64 {
184 return Err(ConstraintError::Minimum {
185 path: ValidationPath::from_field("total_xp"),
186 min: 0i64,
187 actual: *value,
188 });
189 }
190 }
191 if let Some(ref value) = self.xp_gained_since_last_sign {
192 if *value < 0i64 {
193 return Err(ConstraintError::Minimum {
194 path: ValidationPath::from_field("xp_gained_since_last_sign"),
195 min: 0i64,
196 actual: *value,
197 });
198 }
199 }
200 if let Some(ref value) = self.xp_to_next_level {
201 if *value < 0i64 {
202 return Err(ConstraintError::Minimum {
203 path: ValidationPath::from_field("xp_to_next_level"),
204 min: 0i64,
205 actual: *value,
206 });
207 }
208 }
209 Ok(())
210 }
211}
212
213pub mod chronicle_signature_state {
214
215 pub use crate::builder_types::{IsSet, IsUnset, Set, Unset};
216 #[allow(unused)]
217 use ::core::marker::PhantomData;
218 mod sealed {
219 pub trait Sealed {}
220 }
221 pub trait State: sealed::Sealed {
223 type Alg;
224 type Kid;
225 type Nonce;
226 type Sig;
227 type SignedAt;
228 type Version;
229 }
230 pub struct Empty(());
232 impl sealed::Sealed for Empty {}
233 impl State for Empty {
234 type Alg = Unset;
235 type Kid = Unset;
236 type Nonce = Unset;
237 type Sig = Unset;
238 type SignedAt = Unset;
239 type Version = Unset;
240 }
241 pub struct SetAlg<St: State = Empty>(PhantomData<fn() -> St>);
243 impl<St: State> sealed::Sealed for SetAlg<St> {}
244 impl<St: State> State for SetAlg<St> {
245 type Alg = Set<members::alg>;
246 type Kid = St::Kid;
247 type Nonce = St::Nonce;
248 type Sig = St::Sig;
249 type SignedAt = St::SignedAt;
250 type Version = St::Version;
251 }
252 pub struct SetKid<St: State = Empty>(PhantomData<fn() -> St>);
254 impl<St: State> sealed::Sealed for SetKid<St> {}
255 impl<St: State> State for SetKid<St> {
256 type Alg = St::Alg;
257 type Kid = Set<members::kid>;
258 type Nonce = St::Nonce;
259 type Sig = St::Sig;
260 type SignedAt = St::SignedAt;
261 type Version = St::Version;
262 }
263 pub struct SetNonce<St: State = Empty>(PhantomData<fn() -> St>);
265 impl<St: State> sealed::Sealed for SetNonce<St> {}
266 impl<St: State> State for SetNonce<St> {
267 type Alg = St::Alg;
268 type Kid = St::Kid;
269 type Nonce = Set<members::nonce>;
270 type Sig = St::Sig;
271 type SignedAt = St::SignedAt;
272 type Version = St::Version;
273 }
274 pub struct SetSig<St: State = Empty>(PhantomData<fn() -> St>);
276 impl<St: State> sealed::Sealed for SetSig<St> {}
277 impl<St: State> State for SetSig<St> {
278 type Alg = St::Alg;
279 type Kid = St::Kid;
280 type Nonce = St::Nonce;
281 type Sig = Set<members::sig>;
282 type SignedAt = St::SignedAt;
283 type Version = St::Version;
284 }
285 pub struct SetSignedAt<St: State = Empty>(PhantomData<fn() -> St>);
287 impl<St: State> sealed::Sealed for SetSignedAt<St> {}
288 impl<St: State> State for SetSignedAt<St> {
289 type Alg = St::Alg;
290 type Kid = St::Kid;
291 type Nonce = St::Nonce;
292 type Sig = St::Sig;
293 type SignedAt = Set<members::signed_at>;
294 type Version = St::Version;
295 }
296 pub struct SetVersion<St: State = Empty>(PhantomData<fn() -> St>);
298 impl<St: State> sealed::Sealed for SetVersion<St> {}
299 impl<St: State> State for SetVersion<St> {
300 type Alg = St::Alg;
301 type Kid = St::Kid;
302 type Nonce = St::Nonce;
303 type Sig = St::Sig;
304 type SignedAt = St::SignedAt;
305 type Version = Set<members::version>;
306 }
307 #[allow(non_camel_case_types)]
309 pub mod members {
310 pub struct alg(());
312 pub struct kid(());
314 pub struct nonce(());
316 pub struct sig(());
318 pub struct signed_at(());
320 pub struct version(());
322 }
323}
324
325pub struct ChronicleSignatureBuilder<St: chronicle_signature_state::State, S: BosStr = DefaultStr> {
327 _state: PhantomData<fn() -> St>,
328 _fields: (
329 Option<S>,
330 Option<S>,
331 Option<S>,
332 Option<S>,
333 Option<Datetime>,
334 Option<i64>,
335 ),
336 _type: PhantomData<fn() -> S>,
337}
338
339impl ChronicleSignature<DefaultStr> {
340 pub fn new() -> ChronicleSignatureBuilder<chronicle_signature_state::Empty, DefaultStr> {
342 ChronicleSignatureBuilder::new()
343 }
344}
345
346impl<S: BosStr> ChronicleSignature<S> {
347 pub fn builder() -> ChronicleSignatureBuilder<chronicle_signature_state::Empty, S> {
349 ChronicleSignatureBuilder::builder()
350 }
351}
352
353impl ChronicleSignatureBuilder<chronicle_signature_state::Empty, DefaultStr> {
354 pub fn new() -> Self {
356 ChronicleSignatureBuilder {
357 _state: PhantomData,
358 _fields: (None, None, None, None, None, None),
359 _type: PhantomData,
360 }
361 }
362}
363
364impl<S: BosStr> ChronicleSignatureBuilder<chronicle_signature_state::Empty, S> {
365 pub fn builder() -> Self {
367 ChronicleSignatureBuilder {
368 _state: PhantomData,
369 _fields: (None, None, None, None, None, None),
370 _type: PhantomData,
371 }
372 }
373}
374
375impl<St, S: BosStr> ChronicleSignatureBuilder<St, S>
376where
377 St: chronicle_signature_state::State,
378 St::Alg: chronicle_signature_state::IsUnset,
379{
380 pub fn alg(
382 mut self,
383 value: impl Into<S>,
384 ) -> ChronicleSignatureBuilder<chronicle_signature_state::SetAlg<St>, S> {
385 self._fields.0 = Option::Some(value.into());
386 ChronicleSignatureBuilder {
387 _state: PhantomData,
388 _fields: self._fields,
389 _type: PhantomData,
390 }
391 }
392}
393
394impl<St, S: BosStr> ChronicleSignatureBuilder<St, S>
395where
396 St: chronicle_signature_state::State,
397 St::Kid: chronicle_signature_state::IsUnset,
398{
399 pub fn kid(
401 mut self,
402 value: impl Into<S>,
403 ) -> ChronicleSignatureBuilder<chronicle_signature_state::SetKid<St>, S> {
404 self._fields.1 = Option::Some(value.into());
405 ChronicleSignatureBuilder {
406 _state: PhantomData,
407 _fields: self._fields,
408 _type: PhantomData,
409 }
410 }
411}
412
413impl<St, S: BosStr> ChronicleSignatureBuilder<St, S>
414where
415 St: chronicle_signature_state::State,
416 St::Nonce: chronicle_signature_state::IsUnset,
417{
418 pub fn nonce(
420 mut self,
421 value: impl Into<S>,
422 ) -> ChronicleSignatureBuilder<chronicle_signature_state::SetNonce<St>, S> {
423 self._fields.2 = Option::Some(value.into());
424 ChronicleSignatureBuilder {
425 _state: PhantomData,
426 _fields: self._fields,
427 _type: PhantomData,
428 }
429 }
430}
431
432impl<St, S: BosStr> ChronicleSignatureBuilder<St, S>
433where
434 St: chronicle_signature_state::State,
435 St::Sig: chronicle_signature_state::IsUnset,
436{
437 pub fn sig(
439 mut self,
440 value: impl Into<S>,
441 ) -> ChronicleSignatureBuilder<chronicle_signature_state::SetSig<St>, S> {
442 self._fields.3 = Option::Some(value.into());
443 ChronicleSignatureBuilder {
444 _state: PhantomData,
445 _fields: self._fields,
446 _type: PhantomData,
447 }
448 }
449}
450
451impl<St, S: BosStr> ChronicleSignatureBuilder<St, S>
452where
453 St: chronicle_signature_state::State,
454 St::SignedAt: chronicle_signature_state::IsUnset,
455{
456 pub fn signed_at(
458 mut self,
459 value: impl Into<Datetime>,
460 ) -> ChronicleSignatureBuilder<chronicle_signature_state::SetSignedAt<St>, S> {
461 self._fields.4 = Option::Some(value.into());
462 ChronicleSignatureBuilder {
463 _state: PhantomData,
464 _fields: self._fields,
465 _type: PhantomData,
466 }
467 }
468}
469
470impl<St, S: BosStr> ChronicleSignatureBuilder<St, S>
471where
472 St: chronicle_signature_state::State,
473 St::Version: chronicle_signature_state::IsUnset,
474{
475 pub fn version(
477 mut self,
478 value: impl Into<i64>,
479 ) -> ChronicleSignatureBuilder<chronicle_signature_state::SetVersion<St>, S> {
480 self._fields.5 = Option::Some(value.into());
481 ChronicleSignatureBuilder {
482 _state: PhantomData,
483 _fields: self._fields,
484 _type: PhantomData,
485 }
486 }
487}
488
489impl<St, S: BosStr> ChronicleSignatureBuilder<St, S>
490where
491 St: chronicle_signature_state::State,
492 St::Alg: chronicle_signature_state::IsSet,
493 St::Kid: chronicle_signature_state::IsSet,
494 St::Nonce: chronicle_signature_state::IsSet,
495 St::Sig: chronicle_signature_state::IsSet,
496 St::SignedAt: chronicle_signature_state::IsSet,
497 St::Version: chronicle_signature_state::IsSet,
498{
499 pub fn build(self) -> ChronicleSignature<S> {
501 ChronicleSignature {
502 alg: self._fields.0.unwrap(),
503 kid: self._fields.1.unwrap(),
504 nonce: self._fields.2.unwrap(),
505 sig: self._fields.3.unwrap(),
506 signed_at: self._fields.4.unwrap(),
507 version: self._fields.5.unwrap(),
508 extra_data: Default::default(),
509 }
510 }
511 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> ChronicleSignature<S> {
513 ChronicleSignature {
514 alg: self._fields.0.unwrap(),
515 kid: self._fields.1.unwrap(),
516 nonce: self._fields.2.unwrap(),
517 sig: self._fields.3.unwrap(),
518 signed_at: self._fields.4.unwrap(),
519 version: self._fields.5.unwrap(),
520 extra_data: Some(extra_data),
521 }
522 }
523}
524
525fn lexicon_doc_net_anisota_chronicle_progress() -> LexiconDoc<'static> {
526 use alloc::collections::BTreeMap;
527 #[allow(unused_imports)]
528 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
529 use jacquard_lexicon::lexicon::*;
530 LexiconDoc {
531 lexicon: Lexicon::Lexicon1,
532 id: CowStr::new_static("net.anisota.chronicle.progress"),
533 defs: {
534 let mut map = BTreeMap::new();
535 map.insert(
536 SmolStr::new_static("chronicleSignature"),
537 LexUserType::Object(LexObject {
538 description: Some(CowStr::new_static(
539 "ES256 cryptographic signature proving record authenticity",
540 )),
541 required: Some(vec![
542 SmolStr::new_static("sig"),
543 SmolStr::new_static("alg"),
544 SmolStr::new_static("kid"),
545 SmolStr::new_static("signedAt"),
546 SmolStr::new_static("nonce"),
547 SmolStr::new_static("version"),
548 ]),
549 properties: {
550 #[allow(unused_mut)]
551 let mut map = BTreeMap::new();
552 map.insert(
553 SmolStr::new_static("alg"),
554 LexObjectProperty::String(LexString {
555 description: Some(CowStr::new_static("Signing algorithm (ES256)")),
556 ..Default::default()
557 }),
558 );
559 map.insert(
560 SmolStr::new_static("kid"),
561 LexObjectProperty::String(LexString {
562 description: Some(CowStr::new_static(
563 "Key identifier for the signing key",
564 )),
565 ..Default::default()
566 }),
567 );
568 map.insert(
569 SmolStr::new_static("nonce"),
570 LexObjectProperty::String(LexString {
571 description: Some(CowStr::new_static(
572 "Unique random nonce to prevent replay",
573 )),
574 ..Default::default()
575 }),
576 );
577 map.insert(
578 SmolStr::new_static("sig"),
579 LexObjectProperty::String(LexString {
580 description: Some(CowStr::new_static(
581 "Base64-encoded ES256 signature",
582 )),
583 ..Default::default()
584 }),
585 );
586 map.insert(
587 SmolStr::new_static("signedAt"),
588 LexObjectProperty::String(LexString {
589 description: Some(CowStr::new_static("When the record was signed")),
590 format: Some(LexStringFormat::Datetime),
591 ..Default::default()
592 }),
593 );
594 map.insert(
595 SmolStr::new_static("version"),
596 LexObjectProperty::Integer(LexInteger {
597 ..Default::default()
598 }),
599 );
600 map
601 },
602 ..Default::default()
603 }),
604 );
605 map.insert(
606 SmolStr::new_static("main"),
607 LexUserType::Record(LexRecord {
608 description: Some(
609 CowStr::new_static(
610 "Signed player progression state. Singleton (rkey: self), overwritten via putRecord. Backend validates XP claims before signing.",
611 ),
612 ),
613 key: Some(CowStr::new_static("any")),
614 record: LexRecordRecord::Object(LexObject {
615 required: Some(
616 vec![
617 SmolStr::new_static("totalXP"),
618 SmolStr::new_static("level"),
619 SmolStr::new_static("signature"),
620 SmolStr::new_static("createdAt")
621 ],
622 ),
623 properties: {
624 #[allow(unused_mut)]
625 let mut map = BTreeMap::new();
626 map.insert(
627 SmolStr::new_static("createdAt"),
628 LexObjectProperty::String(LexString {
629 description: Some(
630 CowStr::new_static("When the record was first created"),
631 ),
632 format: Some(LexStringFormat::Datetime),
633 ..Default::default()
634 }),
635 );
636 map.insert(
637 SmolStr::new_static("level"),
638 LexObjectProperty::Integer(LexInteger {
639 minimum: Some(1i64),
640 maximum: Some(99i64),
641 ..Default::default()
642 }),
643 );
644 map.insert(
645 SmolStr::new_static("progressPercentage"),
646 LexObjectProperty::String(LexString {
647 description: Some(
648 CowStr::new_static(
649 "Progress toward next level as decimal string",
650 ),
651 ),
652 ..Default::default()
653 }),
654 );
655 map.insert(
656 SmolStr::new_static("signature"),
657 LexObjectProperty::Ref(LexRef {
658 r#ref: CowStr::new_static("#chronicleSignature"),
659 ..Default::default()
660 }),
661 );
662 map.insert(
663 SmolStr::new_static("totalXP"),
664 LexObjectProperty::Integer(LexInteger {
665 minimum: Some(0i64),
666 ..Default::default()
667 }),
668 );
669 map.insert(
670 SmolStr::new_static("triggerSource"),
671 LexObjectProperty::String(LexString {
672 description: Some(
673 CowStr::new_static(
674 "What triggered this save (level_up, session_end, visibility_hidden, periodic, card_advance)",
675 ),
676 ),
677 ..Default::default()
678 }),
679 );
680 map.insert(
681 SmolStr::new_static("updatedAt"),
682 LexObjectProperty::String(LexString {
683 description: Some(
684 CowStr::new_static("When the record was last updated"),
685 ),
686 format: Some(LexStringFormat::Datetime),
687 ..Default::default()
688 }),
689 );
690 map.insert(
691 SmolStr::new_static("xpGainedSinceLastSign"),
692 LexObjectProperty::Integer(LexInteger {
693 minimum: Some(0i64),
694 ..Default::default()
695 }),
696 );
697 map.insert(
698 SmolStr::new_static("xpToNextLevel"),
699 LexObjectProperty::Integer(LexInteger {
700 minimum: Some(0i64),
701 ..Default::default()
702 }),
703 );
704 map
705 },
706 ..Default::default()
707 }),
708 ..Default::default()
709 }),
710 );
711 map
712 },
713 ..Default::default()
714 }
715}
716
717pub mod progress_state {
718
719 pub use crate::builder_types::{IsSet, IsUnset, Set, Unset};
720 #[allow(unused)]
721 use ::core::marker::PhantomData;
722 mod sealed {
723 pub trait Sealed {}
724 }
725 pub trait State: sealed::Sealed {
727 type CreatedAt;
728 type Level;
729 type Signature;
730 type TotalXp;
731 }
732 pub struct Empty(());
734 impl sealed::Sealed for Empty {}
735 impl State for Empty {
736 type CreatedAt = Unset;
737 type Level = Unset;
738 type Signature = Unset;
739 type TotalXp = Unset;
740 }
741 pub struct SetCreatedAt<St: State = Empty>(PhantomData<fn() -> St>);
743 impl<St: State> sealed::Sealed for SetCreatedAt<St> {}
744 impl<St: State> State for SetCreatedAt<St> {
745 type CreatedAt = Set<members::created_at>;
746 type Level = St::Level;
747 type Signature = St::Signature;
748 type TotalXp = St::TotalXp;
749 }
750 pub struct SetLevel<St: State = Empty>(PhantomData<fn() -> St>);
752 impl<St: State> sealed::Sealed for SetLevel<St> {}
753 impl<St: State> State for SetLevel<St> {
754 type CreatedAt = St::CreatedAt;
755 type Level = Set<members::level>;
756 type Signature = St::Signature;
757 type TotalXp = St::TotalXp;
758 }
759 pub struct SetSignature<St: State = Empty>(PhantomData<fn() -> St>);
761 impl<St: State> sealed::Sealed for SetSignature<St> {}
762 impl<St: State> State for SetSignature<St> {
763 type CreatedAt = St::CreatedAt;
764 type Level = St::Level;
765 type Signature = Set<members::signature>;
766 type TotalXp = St::TotalXp;
767 }
768 pub struct SetTotalXp<St: State = Empty>(PhantomData<fn() -> St>);
770 impl<St: State> sealed::Sealed for SetTotalXp<St> {}
771 impl<St: State> State for SetTotalXp<St> {
772 type CreatedAt = St::CreatedAt;
773 type Level = St::Level;
774 type Signature = St::Signature;
775 type TotalXp = Set<members::total_xp>;
776 }
777 #[allow(non_camel_case_types)]
779 pub mod members {
780 pub struct created_at(());
782 pub struct level(());
784 pub struct signature(());
786 pub struct total_xp(());
788 }
789}
790
791pub struct ProgressBuilder<St: progress_state::State, S: BosStr = DefaultStr> {
793 _state: PhantomData<fn() -> St>,
794 _fields: (
795 Option<Datetime>,
796 Option<i64>,
797 Option<S>,
798 Option<progress::ChronicleSignature<S>>,
799 Option<i64>,
800 Option<S>,
801 Option<Datetime>,
802 Option<i64>,
803 Option<i64>,
804 ),
805 _type: PhantomData<fn() -> S>,
806}
807
808impl Progress<DefaultStr> {
809 pub fn new() -> ProgressBuilder<progress_state::Empty, DefaultStr> {
811 ProgressBuilder::new()
812 }
813}
814
815impl<S: BosStr> Progress<S> {
816 pub fn builder() -> ProgressBuilder<progress_state::Empty, S> {
818 ProgressBuilder::builder()
819 }
820}
821
822impl ProgressBuilder<progress_state::Empty, DefaultStr> {
823 pub fn new() -> Self {
825 ProgressBuilder {
826 _state: PhantomData,
827 _fields: (None, None, None, None, None, None, None, None, None),
828 _type: PhantomData,
829 }
830 }
831}
832
833impl<S: BosStr> ProgressBuilder<progress_state::Empty, S> {
834 pub fn builder() -> Self {
836 ProgressBuilder {
837 _state: PhantomData,
838 _fields: (None, None, None, None, None, None, None, None, None),
839 _type: PhantomData,
840 }
841 }
842}
843
844impl<St, S: BosStr> ProgressBuilder<St, S>
845where
846 St: progress_state::State,
847 St::CreatedAt: progress_state::IsUnset,
848{
849 pub fn created_at(
851 mut self,
852 value: impl Into<Datetime>,
853 ) -> ProgressBuilder<progress_state::SetCreatedAt<St>, S> {
854 self._fields.0 = Option::Some(value.into());
855 ProgressBuilder {
856 _state: PhantomData,
857 _fields: self._fields,
858 _type: PhantomData,
859 }
860 }
861}
862
863impl<St, S: BosStr> ProgressBuilder<St, S>
864where
865 St: progress_state::State,
866 St::Level: progress_state::IsUnset,
867{
868 pub fn level(
870 mut self,
871 value: impl Into<i64>,
872 ) -> ProgressBuilder<progress_state::SetLevel<St>, S> {
873 self._fields.1 = Option::Some(value.into());
874 ProgressBuilder {
875 _state: PhantomData,
876 _fields: self._fields,
877 _type: PhantomData,
878 }
879 }
880}
881
882impl<St: progress_state::State, S: BosStr> ProgressBuilder<St, S> {
883 pub fn progress_percentage(mut self, value: impl Into<Option<S>>) -> Self {
885 self._fields.2 = value.into();
886 self
887 }
888 pub fn maybe_progress_percentage(mut self, value: Option<S>) -> Self {
890 self._fields.2 = value;
891 self
892 }
893}
894
895impl<St, S: BosStr> ProgressBuilder<St, S>
896where
897 St: progress_state::State,
898 St::Signature: progress_state::IsUnset,
899{
900 pub fn signature(
902 mut self,
903 value: impl Into<progress::ChronicleSignature<S>>,
904 ) -> ProgressBuilder<progress_state::SetSignature<St>, S> {
905 self._fields.3 = Option::Some(value.into());
906 ProgressBuilder {
907 _state: PhantomData,
908 _fields: self._fields,
909 _type: PhantomData,
910 }
911 }
912}
913
914impl<St, S: BosStr> ProgressBuilder<St, S>
915where
916 St: progress_state::State,
917 St::TotalXp: progress_state::IsUnset,
918{
919 pub fn total_xp(
921 mut self,
922 value: impl Into<i64>,
923 ) -> ProgressBuilder<progress_state::SetTotalXp<St>, S> {
924 self._fields.4 = Option::Some(value.into());
925 ProgressBuilder {
926 _state: PhantomData,
927 _fields: self._fields,
928 _type: PhantomData,
929 }
930 }
931}
932
933impl<St: progress_state::State, S: BosStr> ProgressBuilder<St, S> {
934 pub fn trigger_source(mut self, value: impl Into<Option<S>>) -> Self {
936 self._fields.5 = value.into();
937 self
938 }
939 pub fn maybe_trigger_source(mut self, value: Option<S>) -> Self {
941 self._fields.5 = value;
942 self
943 }
944}
945
946impl<St: progress_state::State, S: BosStr> ProgressBuilder<St, S> {
947 pub fn updated_at(mut self, value: impl Into<Option<Datetime>>) -> Self {
949 self._fields.6 = value.into();
950 self
951 }
952 pub fn maybe_updated_at(mut self, value: Option<Datetime>) -> Self {
954 self._fields.6 = value;
955 self
956 }
957}
958
959impl<St: progress_state::State, S: BosStr> ProgressBuilder<St, S> {
960 pub fn xp_gained_since_last_sign(mut self, value: impl Into<Option<i64>>) -> Self {
962 self._fields.7 = value.into();
963 self
964 }
965 pub fn maybe_xp_gained_since_last_sign(mut self, value: Option<i64>) -> Self {
967 self._fields.7 = value;
968 self
969 }
970}
971
972impl<St: progress_state::State, S: BosStr> ProgressBuilder<St, S> {
973 pub fn xp_to_next_level(mut self, value: impl Into<Option<i64>>) -> Self {
975 self._fields.8 = value.into();
976 self
977 }
978 pub fn maybe_xp_to_next_level(mut self, value: Option<i64>) -> Self {
980 self._fields.8 = value;
981 self
982 }
983}
984
985impl<St, S: BosStr> ProgressBuilder<St, S>
986where
987 St: progress_state::State,
988 St::CreatedAt: progress_state::IsSet,
989 St::Level: progress_state::IsSet,
990 St::Signature: progress_state::IsSet,
991 St::TotalXp: progress_state::IsSet,
992{
993 pub fn build(self) -> Progress<S> {
995 Progress {
996 created_at: self._fields.0.unwrap(),
997 level: self._fields.1.unwrap(),
998 progress_percentage: self._fields.2,
999 signature: self._fields.3.unwrap(),
1000 total_xp: self._fields.4.unwrap(),
1001 trigger_source: self._fields.5,
1002 updated_at: self._fields.6,
1003 xp_gained_since_last_sign: self._fields.7,
1004 xp_to_next_level: self._fields.8,
1005 extra_data: Default::default(),
1006 }
1007 }
1008 pub fn build_with_data(self, extra_data: BTreeMap<SmolStr, Data<S>>) -> Progress<S> {
1010 Progress {
1011 created_at: self._fields.0.unwrap(),
1012 level: self._fields.1.unwrap(),
1013 progress_percentage: self._fields.2,
1014 signature: self._fields.3.unwrap(),
1015 total_xp: self._fields.4.unwrap(),
1016 trigger_source: self._fields.5,
1017 updated_at: self._fields.6,
1018 xp_gained_since_last_sign: self._fields.7,
1019 xp_to_next_level: self._fields.8,
1020 extra_data: Some(extra_data),
1021 }
1022 }
1023}