1#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::CowStr;
14
15#[allow(unused_imports)]
16use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
17use jacquard_common::types::string::Datetime;
18use jacquard_derive::{IntoStatic, lexicon, open_union};
19use jacquard_lexicon::lexicon::LexiconDoc;
20use jacquard_lexicon::schema::LexiconSchema;
21
22#[allow(unused_imports)]
23use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
24use serde::{Serialize, Deserialize};
25use crate::sh_tangled::repo::blob;
26
27#[lexicon]
28#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
29#[serde(rename_all = "camelCase")]
30pub struct LastCommit<'a> {
31 #[serde(skip_serializing_if = "Option::is_none")]
32 #[serde(borrow)]
33 pub author: Option<blob::Signature<'a>>,
34 #[serde(borrow)]
36 pub hash: CowStr<'a>,
37 #[serde(borrow)]
39 pub message: CowStr<'a>,
40 pub when: Datetime,
42}
43
44
45#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
46#[serde(rename_all = "camelCase")]
47pub struct Blob<'a> {
48 #[serde(borrow)]
49 pub path: CowStr<'a>,
50 #[serde(default = "_default_raw")]
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub raw: Option<bool>,
54 #[serde(borrow)]
55 pub r#ref: CowStr<'a>,
56 #[serde(borrow)]
57 pub repo: CowStr<'a>,
58}
59
60
61#[lexicon]
62#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
63#[serde(rename_all = "camelCase")]
64pub struct BlobOutput<'a> {
65 #[serde(skip_serializing_if = "Option::is_none")]
67 #[serde(borrow)]
68 pub content: Option<CowStr<'a>>,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 #[serde(borrow)]
72 pub encoding: Option<CowStr<'a>>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub is_binary: Option<bool>,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 #[serde(borrow)]
78 pub last_commit: Option<blob::LastCommit<'a>>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 #[serde(borrow)]
82 pub mime_type: Option<CowStr<'a>>,
83 #[serde(borrow)]
85 pub path: CowStr<'a>,
86 #[serde(borrow)]
88 pub r#ref: CowStr<'a>,
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub size: Option<i64>,
92 #[serde(skip_serializing_if = "Option::is_none")]
94 #[serde(borrow)]
95 pub submodule: Option<blob::Submodule<'a>>,
96}
97
98
99#[open_union]
100#[derive(
101 Serialize,
102 Deserialize,
103 Debug,
104 Clone,
105 PartialEq,
106 Eq,
107 thiserror::Error,
108 miette::Diagnostic,
109 IntoStatic
110)]
111
112#[serde(tag = "error", content = "message")]
113#[serde(bound(deserialize = "'de: 'a"))]
114pub enum BlobError<'a> {
115 #[serde(rename = "RepoNotFound")]
117 RepoNotFound(Option<CowStr<'a>>),
118 #[serde(rename = "RefNotFound")]
120 RefNotFound(Option<CowStr<'a>>),
121 #[serde(rename = "FileNotFound")]
123 FileNotFound(Option<CowStr<'a>>),
124 #[serde(rename = "InvalidRequest")]
126 InvalidRequest(Option<CowStr<'a>>),
127}
128
129impl core::fmt::Display for BlobError<'_> {
130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
131 match self {
132 Self::RepoNotFound(msg) => {
133 write!(f, "RepoNotFound")?;
134 if let Some(msg) = msg {
135 write!(f, ": {}", msg)?;
136 }
137 Ok(())
138 }
139 Self::RefNotFound(msg) => {
140 write!(f, "RefNotFound")?;
141 if let Some(msg) = msg {
142 write!(f, ": {}", msg)?;
143 }
144 Ok(())
145 }
146 Self::FileNotFound(msg) => {
147 write!(f, "FileNotFound")?;
148 if let Some(msg) = msg {
149 write!(f, ": {}", msg)?;
150 }
151 Ok(())
152 }
153 Self::InvalidRequest(msg) => {
154 write!(f, "InvalidRequest")?;
155 if let Some(msg) = msg {
156 write!(f, ": {}", msg)?;
157 }
158 Ok(())
159 }
160 Self::Unknown(err) => write!(f, "Unknown error: {:?}", err),
161 }
162 }
163}
164
165
166#[lexicon]
167#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
168#[serde(rename_all = "camelCase")]
169pub struct Signature<'a> {
170 #[serde(borrow)]
172 pub email: CowStr<'a>,
173 #[serde(borrow)]
175 pub name: CowStr<'a>,
176 pub when: Datetime,
178}
179
180
181#[lexicon]
182#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic, Default)]
183#[serde(rename_all = "camelCase")]
184pub struct Submodule<'a> {
185 #[serde(skip_serializing_if = "Option::is_none")]
187 #[serde(borrow)]
188 pub branch: Option<CowStr<'a>>,
189 #[serde(borrow)]
191 pub name: CowStr<'a>,
192 #[serde(borrow)]
194 pub url: CowStr<'a>,
195}
196
197impl<'a> LexiconSchema for LastCommit<'a> {
198 fn nsid() -> &'static str {
199 "sh.tangled.repo.blob"
200 }
201 fn def_name() -> &'static str {
202 "lastCommit"
203 }
204 fn lexicon_doc() -> LexiconDoc<'static> {
205 lexicon_doc_sh_tangled_repo_blob()
206 }
207 fn validate(&self) -> Result<(), ConstraintError> {
208 Ok(())
209 }
210}
211
212pub struct BlobResponse;
214impl jacquard_common::xrpc::XrpcResp for BlobResponse {
215 const NSID: &'static str = "sh.tangled.repo.blob";
216 const ENCODING: &'static str = "application/json";
217 type Output<'de> = BlobOutput<'de>;
218 type Err<'de> = BlobError<'de>;
219}
220
221impl<'a> jacquard_common::xrpc::XrpcRequest for Blob<'a> {
222 const NSID: &'static str = "sh.tangled.repo.blob";
223 const METHOD: jacquard_common::xrpc::XrpcMethod = jacquard_common::xrpc::XrpcMethod::Query;
224 type Response = BlobResponse;
225}
226
227pub struct BlobRequest;
229impl jacquard_common::xrpc::XrpcEndpoint for BlobRequest {
230 const PATH: &'static str = "/xrpc/sh.tangled.repo.blob";
231 const METHOD: jacquard_common::xrpc::XrpcMethod = jacquard_common::xrpc::XrpcMethod::Query;
232 type Request<'de> = Blob<'de>;
233 type Response = BlobResponse;
234}
235
236impl<'a> LexiconSchema for Signature<'a> {
237 fn nsid() -> &'static str {
238 "sh.tangled.repo.blob"
239 }
240 fn def_name() -> &'static str {
241 "signature"
242 }
243 fn lexicon_doc() -> LexiconDoc<'static> {
244 lexicon_doc_sh_tangled_repo_blob()
245 }
246 fn validate(&self) -> Result<(), ConstraintError> {
247 Ok(())
248 }
249}
250
251impl<'a> LexiconSchema for Submodule<'a> {
252 fn nsid() -> &'static str {
253 "sh.tangled.repo.blob"
254 }
255 fn def_name() -> &'static str {
256 "submodule"
257 }
258 fn lexicon_doc() -> LexiconDoc<'static> {
259 lexicon_doc_sh_tangled_repo_blob()
260 }
261 fn validate(&self) -> Result<(), ConstraintError> {
262 Ok(())
263 }
264}
265
266pub mod last_commit_state {
267
268 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
269 #[allow(unused)]
270 use ::core::marker::PhantomData;
271 mod sealed {
272 pub trait Sealed {}
273 }
274 pub trait State: sealed::Sealed {
276 type Hash;
277 type Message;
278 type When;
279 }
280 pub struct Empty(());
282 impl sealed::Sealed for Empty {}
283 impl State for Empty {
284 type Hash = Unset;
285 type Message = Unset;
286 type When = Unset;
287 }
288 pub struct SetHash<S: State = Empty>(PhantomData<fn() -> S>);
290 impl<S: State> sealed::Sealed for SetHash<S> {}
291 impl<S: State> State for SetHash<S> {
292 type Hash = Set<members::hash>;
293 type Message = S::Message;
294 type When = S::When;
295 }
296 pub struct SetMessage<S: State = Empty>(PhantomData<fn() -> S>);
298 impl<S: State> sealed::Sealed for SetMessage<S> {}
299 impl<S: State> State for SetMessage<S> {
300 type Hash = S::Hash;
301 type Message = Set<members::message>;
302 type When = S::When;
303 }
304 pub struct SetWhen<S: State = Empty>(PhantomData<fn() -> S>);
306 impl<S: State> sealed::Sealed for SetWhen<S> {}
307 impl<S: State> State for SetWhen<S> {
308 type Hash = S::Hash;
309 type Message = S::Message;
310 type When = Set<members::when>;
311 }
312 #[allow(non_camel_case_types)]
314 pub mod members {
315 pub struct hash(());
317 pub struct message(());
319 pub struct when(());
321 }
322}
323
324pub struct LastCommitBuilder<'a, S: last_commit_state::State> {
326 _state: PhantomData<fn() -> S>,
327 _fields: (
328 Option<blob::Signature<'a>>,
329 Option<CowStr<'a>>,
330 Option<CowStr<'a>>,
331 Option<Datetime>,
332 ),
333 _lifetime: PhantomData<&'a ()>,
334}
335
336impl<'a> LastCommit<'a> {
337 pub fn new() -> LastCommitBuilder<'a, last_commit_state::Empty> {
339 LastCommitBuilder::new()
340 }
341}
342
343impl<'a> LastCommitBuilder<'a, last_commit_state::Empty> {
344 pub fn new() -> Self {
346 LastCommitBuilder {
347 _state: PhantomData,
348 _fields: (None, None, None, None),
349 _lifetime: PhantomData,
350 }
351 }
352}
353
354impl<'a, S: last_commit_state::State> LastCommitBuilder<'a, S> {
355 pub fn author(mut self, value: impl Into<Option<blob::Signature<'a>>>) -> Self {
357 self._fields.0 = value.into();
358 self
359 }
360 pub fn maybe_author(mut self, value: Option<blob::Signature<'a>>) -> Self {
362 self._fields.0 = value;
363 self
364 }
365}
366
367impl<'a, S> LastCommitBuilder<'a, S>
368where
369 S: last_commit_state::State,
370 S::Hash: last_commit_state::IsUnset,
371{
372 pub fn hash(
374 mut self,
375 value: impl Into<CowStr<'a>>,
376 ) -> LastCommitBuilder<'a, last_commit_state::SetHash<S>> {
377 self._fields.1 = Option::Some(value.into());
378 LastCommitBuilder {
379 _state: PhantomData,
380 _fields: self._fields,
381 _lifetime: PhantomData,
382 }
383 }
384}
385
386impl<'a, S> LastCommitBuilder<'a, S>
387where
388 S: last_commit_state::State,
389 S::Message: last_commit_state::IsUnset,
390{
391 pub fn message(
393 mut self,
394 value: impl Into<CowStr<'a>>,
395 ) -> LastCommitBuilder<'a, last_commit_state::SetMessage<S>> {
396 self._fields.2 = Option::Some(value.into());
397 LastCommitBuilder {
398 _state: PhantomData,
399 _fields: self._fields,
400 _lifetime: PhantomData,
401 }
402 }
403}
404
405impl<'a, S> LastCommitBuilder<'a, S>
406where
407 S: last_commit_state::State,
408 S::When: last_commit_state::IsUnset,
409{
410 pub fn when(
412 mut self,
413 value: impl Into<Datetime>,
414 ) -> LastCommitBuilder<'a, last_commit_state::SetWhen<S>> {
415 self._fields.3 = Option::Some(value.into());
416 LastCommitBuilder {
417 _state: PhantomData,
418 _fields: self._fields,
419 _lifetime: PhantomData,
420 }
421 }
422}
423
424impl<'a, S> LastCommitBuilder<'a, S>
425where
426 S: last_commit_state::State,
427 S::Hash: last_commit_state::IsSet,
428 S::Message: last_commit_state::IsSet,
429 S::When: last_commit_state::IsSet,
430{
431 pub fn build(self) -> LastCommit<'a> {
433 LastCommit {
434 author: self._fields.0,
435 hash: self._fields.1.unwrap(),
436 message: self._fields.2.unwrap(),
437 when: self._fields.3.unwrap(),
438 extra_data: Default::default(),
439 }
440 }
441 pub fn build_with_data(
443 self,
444 extra_data: BTreeMap<
445 jacquard_common::deps::smol_str::SmolStr,
446 jacquard_common::types::value::Data<'a>,
447 >,
448 ) -> LastCommit<'a> {
449 LastCommit {
450 author: self._fields.0,
451 hash: self._fields.1.unwrap(),
452 message: self._fields.2.unwrap(),
453 when: self._fields.3.unwrap(),
454 extra_data: Some(extra_data),
455 }
456 }
457}
458
459fn lexicon_doc_sh_tangled_repo_blob() -> LexiconDoc<'static> {
460 #[allow(unused_imports)]
461 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
462 use jacquard_lexicon::lexicon::*;
463 use alloc::collections::BTreeMap;
464 LexiconDoc {
465 lexicon: Lexicon::Lexicon1,
466 id: CowStr::new_static("sh.tangled.repo.blob"),
467 defs: {
468 let mut map = BTreeMap::new();
469 map.insert(
470 SmolStr::new_static("lastCommit"),
471 LexUserType::Object(LexObject {
472 required: Some(
473 vec![
474 SmolStr::new_static("hash"), SmolStr::new_static("message"),
475 SmolStr::new_static("when")
476 ],
477 ),
478 properties: {
479 #[allow(unused_mut)]
480 let mut map = BTreeMap::new();
481 map.insert(
482 SmolStr::new_static("author"),
483 LexObjectProperty::Ref(LexRef {
484 r#ref: CowStr::new_static("#signature"),
485 ..Default::default()
486 }),
487 );
488 map.insert(
489 SmolStr::new_static("hash"),
490 LexObjectProperty::String(LexString {
491 description: Some(CowStr::new_static("Commit hash")),
492 ..Default::default()
493 }),
494 );
495 map.insert(
496 SmolStr::new_static("message"),
497 LexObjectProperty::String(LexString {
498 description: Some(CowStr::new_static("Commit message")),
499 ..Default::default()
500 }),
501 );
502 map.insert(
503 SmolStr::new_static("when"),
504 LexObjectProperty::String(LexString {
505 description: Some(CowStr::new_static("Commit timestamp")),
506 format: Some(LexStringFormat::Datetime),
507 ..Default::default()
508 }),
509 );
510 map
511 },
512 ..Default::default()
513 }),
514 );
515 map.insert(
516 SmolStr::new_static("main"),
517 LexUserType::XrpcQuery(LexXrpcQuery {
518 parameters: Some(
519 LexXrpcQueryParameter::Params(LexXrpcParameters {
520 required: Some(
521 vec![
522 SmolStr::new_static("repo"), SmolStr::new_static("ref"),
523 SmolStr::new_static("path")
524 ],
525 ),
526 properties: {
527 #[allow(unused_mut)]
528 let mut map = BTreeMap::new();
529 map.insert(
530 SmolStr::new_static("path"),
531 LexXrpcParametersProperty::String(LexString {
532 description: Some(
533 CowStr::new_static("Path to the file within the repository"),
534 ),
535 ..Default::default()
536 }),
537 );
538 map.insert(
539 SmolStr::new_static("raw"),
540 LexXrpcParametersProperty::Boolean(LexBoolean {
541 ..Default::default()
542 }),
543 );
544 map.insert(
545 SmolStr::new_static("ref"),
546 LexXrpcParametersProperty::String(LexString {
547 description: Some(
548 CowStr::new_static(
549 "Git reference (branch, tag, or commit SHA)",
550 ),
551 ),
552 ..Default::default()
553 }),
554 );
555 map.insert(
556 SmolStr::new_static("repo"),
557 LexXrpcParametersProperty::String(LexString {
558 description: Some(
559 CowStr::new_static(
560 "Repository identifier in format 'did:plc:.../repoName'",
561 ),
562 ),
563 ..Default::default()
564 }),
565 );
566 map
567 },
568 ..Default::default()
569 }),
570 ),
571 ..Default::default()
572 }),
573 );
574 map.insert(
575 SmolStr::new_static("signature"),
576 LexUserType::Object(LexObject {
577 required: Some(
578 vec![
579 SmolStr::new_static("name"), SmolStr::new_static("email"),
580 SmolStr::new_static("when")
581 ],
582 ),
583 properties: {
584 #[allow(unused_mut)]
585 let mut map = BTreeMap::new();
586 map.insert(
587 SmolStr::new_static("email"),
588 LexObjectProperty::String(LexString {
589 description: Some(CowStr::new_static("Author email")),
590 ..Default::default()
591 }),
592 );
593 map.insert(
594 SmolStr::new_static("name"),
595 LexObjectProperty::String(LexString {
596 description: Some(CowStr::new_static("Author name")),
597 ..Default::default()
598 }),
599 );
600 map.insert(
601 SmolStr::new_static("when"),
602 LexObjectProperty::String(LexString {
603 description: Some(CowStr::new_static("Author timestamp")),
604 format: Some(LexStringFormat::Datetime),
605 ..Default::default()
606 }),
607 );
608 map
609 },
610 ..Default::default()
611 }),
612 );
613 map.insert(
614 SmolStr::new_static("submodule"),
615 LexUserType::Object(LexObject {
616 required: Some(
617 vec![SmolStr::new_static("name"), SmolStr::new_static("url")],
618 ),
619 properties: {
620 #[allow(unused_mut)]
621 let mut map = BTreeMap::new();
622 map.insert(
623 SmolStr::new_static("branch"),
624 LexObjectProperty::String(LexString {
625 description: Some(
626 CowStr::new_static("Branch to track in the submodule"),
627 ),
628 ..Default::default()
629 }),
630 );
631 map.insert(
632 SmolStr::new_static("name"),
633 LexObjectProperty::String(LexString {
634 description: Some(CowStr::new_static("Submodule name")),
635 ..Default::default()
636 }),
637 );
638 map.insert(
639 SmolStr::new_static("url"),
640 LexObjectProperty::String(LexString {
641 description: Some(
642 CowStr::new_static("Submodule repository URL"),
643 ),
644 ..Default::default()
645 }),
646 );
647 map
648 },
649 ..Default::default()
650 }),
651 );
652 map
653 },
654 ..Default::default()
655 }
656}
657
658fn _default_raw() -> Option<bool> {
659 Some(false)
660}
661
662pub mod blob_state {
663
664 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
665 #[allow(unused)]
666 use ::core::marker::PhantomData;
667 mod sealed {
668 pub trait Sealed {}
669 }
670 pub trait State: sealed::Sealed {
672 type Ref;
673 type Path;
674 type Repo;
675 }
676 pub struct Empty(());
678 impl sealed::Sealed for Empty {}
679 impl State for Empty {
680 type Ref = Unset;
681 type Path = Unset;
682 type Repo = Unset;
683 }
684 pub struct SetRef<S: State = Empty>(PhantomData<fn() -> S>);
686 impl<S: State> sealed::Sealed for SetRef<S> {}
687 impl<S: State> State for SetRef<S> {
688 type Ref = Set<members::r#ref>;
689 type Path = S::Path;
690 type Repo = S::Repo;
691 }
692 pub struct SetPath<S: State = Empty>(PhantomData<fn() -> S>);
694 impl<S: State> sealed::Sealed for SetPath<S> {}
695 impl<S: State> State for SetPath<S> {
696 type Ref = S::Ref;
697 type Path = Set<members::path>;
698 type Repo = S::Repo;
699 }
700 pub struct SetRepo<S: State = Empty>(PhantomData<fn() -> S>);
702 impl<S: State> sealed::Sealed for SetRepo<S> {}
703 impl<S: State> State for SetRepo<S> {
704 type Ref = S::Ref;
705 type Path = S::Path;
706 type Repo = Set<members::repo>;
707 }
708 #[allow(non_camel_case_types)]
710 pub mod members {
711 pub struct r#ref(());
713 pub struct path(());
715 pub struct repo(());
717 }
718}
719
720pub struct BlobBuilder<'a, S: blob_state::State> {
722 _state: PhantomData<fn() -> S>,
723 _fields: (Option<CowStr<'a>>, Option<bool>, Option<CowStr<'a>>, Option<CowStr<'a>>),
724 _lifetime: PhantomData<&'a ()>,
725}
726
727impl<'a> Blob<'a> {
728 pub fn new() -> BlobBuilder<'a, blob_state::Empty> {
730 BlobBuilder::new()
731 }
732}
733
734impl<'a> BlobBuilder<'a, blob_state::Empty> {
735 pub fn new() -> Self {
737 BlobBuilder {
738 _state: PhantomData,
739 _fields: (None, None, None, None),
740 _lifetime: PhantomData,
741 }
742 }
743}
744
745impl<'a, S> BlobBuilder<'a, S>
746where
747 S: blob_state::State,
748 S::Path: blob_state::IsUnset,
749{
750 pub fn path(
752 mut self,
753 value: impl Into<CowStr<'a>>,
754 ) -> BlobBuilder<'a, blob_state::SetPath<S>> {
755 self._fields.0 = Option::Some(value.into());
756 BlobBuilder {
757 _state: PhantomData,
758 _fields: self._fields,
759 _lifetime: PhantomData,
760 }
761 }
762}
763
764impl<'a, S: blob_state::State> BlobBuilder<'a, S> {
765 pub fn raw(mut self, value: impl Into<Option<bool>>) -> Self {
767 self._fields.1 = value.into();
768 self
769 }
770 pub fn maybe_raw(mut self, value: Option<bool>) -> Self {
772 self._fields.1 = value;
773 self
774 }
775}
776
777impl<'a, S> BlobBuilder<'a, S>
778where
779 S: blob_state::State,
780 S::Ref: blob_state::IsUnset,
781{
782 pub fn r#ref(
784 mut self,
785 value: impl Into<CowStr<'a>>,
786 ) -> BlobBuilder<'a, blob_state::SetRef<S>> {
787 self._fields.2 = Option::Some(value.into());
788 BlobBuilder {
789 _state: PhantomData,
790 _fields: self._fields,
791 _lifetime: PhantomData,
792 }
793 }
794}
795
796impl<'a, S> BlobBuilder<'a, S>
797where
798 S: blob_state::State,
799 S::Repo: blob_state::IsUnset,
800{
801 pub fn repo(
803 mut self,
804 value: impl Into<CowStr<'a>>,
805 ) -> BlobBuilder<'a, blob_state::SetRepo<S>> {
806 self._fields.3 = Option::Some(value.into());
807 BlobBuilder {
808 _state: PhantomData,
809 _fields: self._fields,
810 _lifetime: PhantomData,
811 }
812 }
813}
814
815impl<'a, S> BlobBuilder<'a, S>
816where
817 S: blob_state::State,
818 S::Ref: blob_state::IsSet,
819 S::Path: blob_state::IsSet,
820 S::Repo: blob_state::IsSet,
821{
822 pub fn build(self) -> Blob<'a> {
824 Blob {
825 path: self._fields.0.unwrap(),
826 raw: self._fields.1,
827 r#ref: self._fields.2.unwrap(),
828 repo: self._fields.3.unwrap(),
829 }
830 }
831}
832
833pub mod signature_state {
834
835 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
836 #[allow(unused)]
837 use ::core::marker::PhantomData;
838 mod sealed {
839 pub trait Sealed {}
840 }
841 pub trait State: sealed::Sealed {
843 type When;
844 type Name;
845 type Email;
846 }
847 pub struct Empty(());
849 impl sealed::Sealed for Empty {}
850 impl State for Empty {
851 type When = Unset;
852 type Name = Unset;
853 type Email = Unset;
854 }
855 pub struct SetWhen<S: State = Empty>(PhantomData<fn() -> S>);
857 impl<S: State> sealed::Sealed for SetWhen<S> {}
858 impl<S: State> State for SetWhen<S> {
859 type When = Set<members::when>;
860 type Name = S::Name;
861 type Email = S::Email;
862 }
863 pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>);
865 impl<S: State> sealed::Sealed for SetName<S> {}
866 impl<S: State> State for SetName<S> {
867 type When = S::When;
868 type Name = Set<members::name>;
869 type Email = S::Email;
870 }
871 pub struct SetEmail<S: State = Empty>(PhantomData<fn() -> S>);
873 impl<S: State> sealed::Sealed for SetEmail<S> {}
874 impl<S: State> State for SetEmail<S> {
875 type When = S::When;
876 type Name = S::Name;
877 type Email = Set<members::email>;
878 }
879 #[allow(non_camel_case_types)]
881 pub mod members {
882 pub struct when(());
884 pub struct name(());
886 pub struct email(());
888 }
889}
890
891pub struct SignatureBuilder<'a, S: signature_state::State> {
893 _state: PhantomData<fn() -> S>,
894 _fields: (Option<CowStr<'a>>, Option<CowStr<'a>>, Option<Datetime>),
895 _lifetime: PhantomData<&'a ()>,
896}
897
898impl<'a> Signature<'a> {
899 pub fn new() -> SignatureBuilder<'a, signature_state::Empty> {
901 SignatureBuilder::new()
902 }
903}
904
905impl<'a> SignatureBuilder<'a, signature_state::Empty> {
906 pub fn new() -> Self {
908 SignatureBuilder {
909 _state: PhantomData,
910 _fields: (None, None, None),
911 _lifetime: PhantomData,
912 }
913 }
914}
915
916impl<'a, S> SignatureBuilder<'a, S>
917where
918 S: signature_state::State,
919 S::Email: signature_state::IsUnset,
920{
921 pub fn email(
923 mut self,
924 value: impl Into<CowStr<'a>>,
925 ) -> SignatureBuilder<'a, signature_state::SetEmail<S>> {
926 self._fields.0 = Option::Some(value.into());
927 SignatureBuilder {
928 _state: PhantomData,
929 _fields: self._fields,
930 _lifetime: PhantomData,
931 }
932 }
933}
934
935impl<'a, S> SignatureBuilder<'a, S>
936where
937 S: signature_state::State,
938 S::Name: signature_state::IsUnset,
939{
940 pub fn name(
942 mut self,
943 value: impl Into<CowStr<'a>>,
944 ) -> SignatureBuilder<'a, signature_state::SetName<S>> {
945 self._fields.1 = Option::Some(value.into());
946 SignatureBuilder {
947 _state: PhantomData,
948 _fields: self._fields,
949 _lifetime: PhantomData,
950 }
951 }
952}
953
954impl<'a, S> SignatureBuilder<'a, S>
955where
956 S: signature_state::State,
957 S::When: signature_state::IsUnset,
958{
959 pub fn when(
961 mut self,
962 value: impl Into<Datetime>,
963 ) -> SignatureBuilder<'a, signature_state::SetWhen<S>> {
964 self._fields.2 = Option::Some(value.into());
965 SignatureBuilder {
966 _state: PhantomData,
967 _fields: self._fields,
968 _lifetime: PhantomData,
969 }
970 }
971}
972
973impl<'a, S> SignatureBuilder<'a, S>
974where
975 S: signature_state::State,
976 S::When: signature_state::IsSet,
977 S::Name: signature_state::IsSet,
978 S::Email: signature_state::IsSet,
979{
980 pub fn build(self) -> Signature<'a> {
982 Signature {
983 email: self._fields.0.unwrap(),
984 name: self._fields.1.unwrap(),
985 when: self._fields.2.unwrap(),
986 extra_data: Default::default(),
987 }
988 }
989 pub fn build_with_data(
991 self,
992 extra_data: BTreeMap<
993 jacquard_common::deps::smol_str::SmolStr,
994 jacquard_common::types::value::Data<'a>,
995 >,
996 ) -> Signature<'a> {
997 Signature {
998 email: self._fields.0.unwrap(),
999 name: self._fields.1.unwrap(),
1000 when: self._fields.2.unwrap(),
1001 extra_data: Some(extra_data),
1002 }
1003 }
1004}