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::blob::BlobRef;
18use jacquard_common::types::string::{Cid, Language, UriValue};
19use jacquard_derive::{IntoStatic, lexicon, open_union};
20use jacquard_lexicon::lexicon::LexiconDoc;
21use jacquard_lexicon::schema::LexiconSchema;
22
23#[allow(unused_imports)]
24use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
25use serde::{Serialize, Deserialize};
26use crate::app_bsky::embed::AspectRatio;
27use crate::sh_weaver::embed::PercentSize;
28use crate::sh_weaver::embed::PixelSize;
29use crate::sh_weaver::embed::video;
30
31#[lexicon]
32#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
33#[serde(rename_all = "camelCase")]
34pub struct Caption<'a> {
35 #[serde(borrow)]
36 pub file: BlobRef<'a>,
37 pub lang: Language,
38}
39
40
41#[lexicon]
42#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
43#[serde(rename_all = "camelCase")]
44pub struct VideoRecord<'a> {
45 #[serde(borrow)]
46 pub videos: Vec<video::Video<'a>>,
47}
48
49
50#[lexicon]
51#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
52#[serde(rename_all = "camelCase")]
53pub struct Video<'a> {
54 #[serde(skip_serializing_if = "Option::is_none")]
56 #[serde(borrow)]
57 pub alt: Option<CowStr<'a>>,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 #[serde(borrow)]
60 pub captions: Option<Vec<video::Caption<'a>>>,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 #[serde(borrow)]
63 pub dimensions: Option<VideoDimensions<'a>>,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 #[serde(borrow)]
66 pub name: Option<CowStr<'a>>,
67 #[serde(borrow)]
69 pub video: BlobRef<'a>,
70}
71
72
73#[open_union]
74#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
75#[serde(tag = "$type", bound(deserialize = "'de: 'a"))]
76pub enum VideoDimensions<'a> {
77 #[serde(rename = "app.bsky.embed.defs#aspectRatio")]
78 AspectRatio(Box<AspectRatio<'a>>),
79 #[serde(rename = "sh.weaver.embed.defs#percentSize")]
80 PercentSize(Box<PercentSize<'a>>),
81 #[serde(rename = "sh.weaver.embed.defs#pixelSize")]
82 PixelSize(Box<PixelSize<'a>>),
83}
84
85
86#[lexicon]
87#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
88#[serde(rename_all = "camelCase")]
89pub struct View<'a> {
90 #[serde(skip_serializing_if = "Option::is_none")]
91 #[serde(borrow)]
92 pub alt: Option<CowStr<'a>>,
93 #[serde(borrow)]
94 pub cid: Cid<'a>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 #[serde(borrow)]
97 pub dimensions: Option<ViewDimensions<'a>>,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 #[serde(borrow)]
100 pub name: Option<CowStr<'a>>,
101 #[serde(borrow)]
102 pub playlist: UriValue<'a>,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 #[serde(borrow)]
105 pub thumbnail: Option<UriValue<'a>>,
106}
107
108
109#[open_union]
110#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
111#[serde(tag = "$type", bound(deserialize = "'de: 'a"))]
112pub enum ViewDimensions<'a> {
113 #[serde(rename = "app.bsky.embed.defs#aspectRatio")]
114 AspectRatio(Box<AspectRatio<'a>>),
115 #[serde(rename = "sh.weaver.embed.defs#percentSize")]
116 PercentSize(Box<PercentSize<'a>>),
117 #[serde(rename = "sh.weaver.embed.defs#pixelSize")]
118 PixelSize(Box<PixelSize<'a>>),
119}
120
121impl<'a> LexiconSchema for Caption<'a> {
122 fn nsid() -> &'static str {
123 "sh.weaver.embed.video"
124 }
125 fn def_name() -> &'static str {
126 "caption"
127 }
128 fn lexicon_doc() -> LexiconDoc<'static> {
129 lexicon_doc_sh_weaver_embed_video()
130 }
131 fn validate(&self) -> Result<(), ConstraintError> {
132 {
133 let value = &self.file;
134 {
135 let size = value.blob().size;
136 if size > 20000usize {
137 return Err(ConstraintError::BlobTooLarge {
138 path: ValidationPath::from_field("file"),
139 max: 20000usize,
140 actual: size,
141 });
142 }
143 }
144 }
145 {
146 let value = &self.file;
147 {
148 let mime = value.blob().mime_type.as_str();
149 let accepted: &[&str] = &["text/vtt"];
150 let matched = accepted
151 .iter()
152 .any(|pattern| {
153 if *pattern == "*/*" {
154 true
155 } else if pattern.ends_with("/*") {
156 let prefix = &pattern[..pattern.len() - 2];
157 mime.starts_with(prefix)
158 && mime.as_bytes().get(prefix.len()) == Some(&b'/')
159 } else {
160 mime == *pattern
161 }
162 });
163 if !matched {
164 return Err(ConstraintError::BlobMimeTypeNotAccepted {
165 path: ValidationPath::from_field("file"),
166 accepted: vec!["text/vtt".to_string()],
167 actual: mime.to_string(),
168 });
169 }
170 }
171 }
172 Ok(())
173 }
174}
175
176impl<'a> LexiconSchema for VideoRecord<'a> {
177 fn nsid() -> &'static str {
178 "sh.weaver.embed.video"
179 }
180 fn def_name() -> &'static str {
181 "main"
182 }
183 fn lexicon_doc() -> LexiconDoc<'static> {
184 lexicon_doc_sh_weaver_embed_video()
185 }
186 fn validate(&self) -> Result<(), ConstraintError> {
187 Ok(())
188 }
189}
190
191impl<'a> LexiconSchema for Video<'a> {
192 fn nsid() -> &'static str {
193 "sh.weaver.embed.video"
194 }
195 fn def_name() -> &'static str {
196 "video"
197 }
198 fn lexicon_doc() -> LexiconDoc<'static> {
199 lexicon_doc_sh_weaver_embed_video()
200 }
201 fn validate(&self) -> Result<(), ConstraintError> {
202 if let Some(ref value) = self.alt {
203 #[allow(unused_comparisons)]
204 if <str>::len(value.as_ref()) > 10000usize {
205 return Err(ConstraintError::MaxLength {
206 path: ValidationPath::from_field("alt"),
207 max: 10000usize,
208 actual: <str>::len(value.as_ref()),
209 });
210 }
211 }
212 if let Some(ref value) = self.alt {
213 {
214 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
215 if count > 1000usize {
216 return Err(ConstraintError::MaxGraphemes {
217 path: ValidationPath::from_field("alt"),
218 max: 1000usize,
219 actual: count,
220 });
221 }
222 }
223 }
224 if let Some(ref value) = self.captions {
225 #[allow(unused_comparisons)]
226 if value.len() > 20usize {
227 return Err(ConstraintError::MaxLength {
228 path: ValidationPath::from_field("captions"),
229 max: 20usize,
230 actual: value.len(),
231 });
232 }
233 }
234 if let Some(ref value) = self.name {
235 #[allow(unused_comparisons)]
236 if <str>::len(value.as_ref()) > 128usize {
237 return Err(ConstraintError::MaxLength {
238 path: ValidationPath::from_field("name"),
239 max: 128usize,
240 actual: <str>::len(value.as_ref()),
241 });
242 }
243 }
244 {
245 let value = &self.video;
246 {
247 let size = value.blob().size;
248 if size > 100000000usize {
249 return Err(ConstraintError::BlobTooLarge {
250 path: ValidationPath::from_field("video"),
251 max: 100000000usize,
252 actual: size,
253 });
254 }
255 }
256 }
257 {
258 let value = &self.video;
259 {
260 let mime = value.blob().mime_type.as_str();
261 let accepted: &[&str] = &["video/mp4"];
262 let matched = accepted
263 .iter()
264 .any(|pattern| {
265 if *pattern == "*/*" {
266 true
267 } else if pattern.ends_with("/*") {
268 let prefix = &pattern[..pattern.len() - 2];
269 mime.starts_with(prefix)
270 && mime.as_bytes().get(prefix.len()) == Some(&b'/')
271 } else {
272 mime == *pattern
273 }
274 });
275 if !matched {
276 return Err(ConstraintError::BlobMimeTypeNotAccepted {
277 path: ValidationPath::from_field("video"),
278 accepted: vec!["video/mp4".to_string()],
279 actual: mime.to_string(),
280 });
281 }
282 }
283 }
284 Ok(())
285 }
286}
287
288impl<'a> LexiconSchema for View<'a> {
289 fn nsid() -> &'static str {
290 "sh.weaver.embed.video"
291 }
292 fn def_name() -> &'static str {
293 "view"
294 }
295 fn lexicon_doc() -> LexiconDoc<'static> {
296 lexicon_doc_sh_weaver_embed_video()
297 }
298 fn validate(&self) -> Result<(), ConstraintError> {
299 if let Some(ref value) = self.alt {
300 #[allow(unused_comparisons)]
301 if <str>::len(value.as_ref()) > 10000usize {
302 return Err(ConstraintError::MaxLength {
303 path: ValidationPath::from_field("alt"),
304 max: 10000usize,
305 actual: <str>::len(value.as_ref()),
306 });
307 }
308 }
309 if let Some(ref value) = self.alt {
310 {
311 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
312 if count > 1000usize {
313 return Err(ConstraintError::MaxGraphemes {
314 path: ValidationPath::from_field("alt"),
315 max: 1000usize,
316 actual: count,
317 });
318 }
319 }
320 }
321 if let Some(ref value) = self.name {
322 #[allow(unused_comparisons)]
323 if <str>::len(value.as_ref()) > 128usize {
324 return Err(ConstraintError::MaxLength {
325 path: ValidationPath::from_field("name"),
326 max: 128usize,
327 actual: <str>::len(value.as_ref()),
328 });
329 }
330 }
331 Ok(())
332 }
333}
334
335pub mod caption_state {
336
337 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
338 #[allow(unused)]
339 use ::core::marker::PhantomData;
340 mod sealed {
341 pub trait Sealed {}
342 }
343 pub trait State: sealed::Sealed {
345 type Lang;
346 type File;
347 }
348 pub struct Empty(());
350 impl sealed::Sealed for Empty {}
351 impl State for Empty {
352 type Lang = Unset;
353 type File = Unset;
354 }
355 pub struct SetLang<S: State = Empty>(PhantomData<fn() -> S>);
357 impl<S: State> sealed::Sealed for SetLang<S> {}
358 impl<S: State> State for SetLang<S> {
359 type Lang = Set<members::lang>;
360 type File = S::File;
361 }
362 pub struct SetFile<S: State = Empty>(PhantomData<fn() -> S>);
364 impl<S: State> sealed::Sealed for SetFile<S> {}
365 impl<S: State> State for SetFile<S> {
366 type Lang = S::Lang;
367 type File = Set<members::file>;
368 }
369 #[allow(non_camel_case_types)]
371 pub mod members {
372 pub struct lang(());
374 pub struct file(());
376 }
377}
378
379pub struct CaptionBuilder<'a, S: caption_state::State> {
381 _state: PhantomData<fn() -> S>,
382 _fields: (Option<BlobRef<'a>>, Option<Language>),
383 _lifetime: PhantomData<&'a ()>,
384}
385
386impl<'a> Caption<'a> {
387 pub fn new() -> CaptionBuilder<'a, caption_state::Empty> {
389 CaptionBuilder::new()
390 }
391}
392
393impl<'a> CaptionBuilder<'a, caption_state::Empty> {
394 pub fn new() -> Self {
396 CaptionBuilder {
397 _state: PhantomData,
398 _fields: (None, None),
399 _lifetime: PhantomData,
400 }
401 }
402}
403
404impl<'a, S> CaptionBuilder<'a, S>
405where
406 S: caption_state::State,
407 S::File: caption_state::IsUnset,
408{
409 pub fn file(
411 mut self,
412 value: impl Into<BlobRef<'a>>,
413 ) -> CaptionBuilder<'a, caption_state::SetFile<S>> {
414 self._fields.0 = Option::Some(value.into());
415 CaptionBuilder {
416 _state: PhantomData,
417 _fields: self._fields,
418 _lifetime: PhantomData,
419 }
420 }
421}
422
423impl<'a, S> CaptionBuilder<'a, S>
424where
425 S: caption_state::State,
426 S::Lang: caption_state::IsUnset,
427{
428 pub fn lang(
430 mut self,
431 value: impl Into<Language>,
432 ) -> CaptionBuilder<'a, caption_state::SetLang<S>> {
433 self._fields.1 = Option::Some(value.into());
434 CaptionBuilder {
435 _state: PhantomData,
436 _fields: self._fields,
437 _lifetime: PhantomData,
438 }
439 }
440}
441
442impl<'a, S> CaptionBuilder<'a, S>
443where
444 S: caption_state::State,
445 S::Lang: caption_state::IsSet,
446 S::File: caption_state::IsSet,
447{
448 pub fn build(self) -> Caption<'a> {
450 Caption {
451 file: self._fields.0.unwrap(),
452 lang: self._fields.1.unwrap(),
453 extra_data: Default::default(),
454 }
455 }
456 pub fn build_with_data(
458 self,
459 extra_data: BTreeMap<
460 jacquard_common::deps::smol_str::SmolStr,
461 jacquard_common::types::value::Data<'a>,
462 >,
463 ) -> Caption<'a> {
464 Caption {
465 file: self._fields.0.unwrap(),
466 lang: self._fields.1.unwrap(),
467 extra_data: Some(extra_data),
468 }
469 }
470}
471
472fn lexicon_doc_sh_weaver_embed_video() -> LexiconDoc<'static> {
473 #[allow(unused_imports)]
474 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
475 use jacquard_lexicon::lexicon::*;
476 use alloc::collections::BTreeMap;
477 LexiconDoc {
478 lexicon: Lexicon::Lexicon1,
479 id: CowStr::new_static("sh.weaver.embed.video"),
480 defs: {
481 let mut map = BTreeMap::new();
482 map.insert(
483 SmolStr::new_static("caption"),
484 LexUserType::Object(LexObject {
485 required: Some(
486 vec![SmolStr::new_static("lang"), SmolStr::new_static("file")],
487 ),
488 properties: {
489 #[allow(unused_mut)]
490 let mut map = BTreeMap::new();
491 map.insert(
492 SmolStr::new_static("file"),
493 LexObjectProperty::Blob(LexBlob { ..Default::default() }),
494 );
495 map.insert(
496 SmolStr::new_static("lang"),
497 LexObjectProperty::String(LexString {
498 format: Some(LexStringFormat::Language),
499 ..Default::default()
500 }),
501 );
502 map
503 },
504 ..Default::default()
505 }),
506 );
507 map.insert(
508 SmolStr::new_static("main"),
509 LexUserType::Object(LexObject {
510 required: Some(vec![SmolStr::new_static("videos")]),
511 properties: {
512 #[allow(unused_mut)]
513 let mut map = BTreeMap::new();
514 map.insert(
515 SmolStr::new_static("videos"),
516 LexObjectProperty::Array(LexArray {
517 items: LexArrayItem::Ref(LexRef {
518 r#ref: CowStr::new_static("#video"),
519 ..Default::default()
520 }),
521 ..Default::default()
522 }),
523 );
524 map
525 },
526 ..Default::default()
527 }),
528 );
529 map.insert(
530 SmolStr::new_static("video"),
531 LexUserType::Object(LexObject {
532 required: Some(vec![SmolStr::new_static("video")]),
533 properties: {
534 #[allow(unused_mut)]
535 let mut map = BTreeMap::new();
536 map.insert(
537 SmolStr::new_static("alt"),
538 LexObjectProperty::String(LexString {
539 description: Some(
540 CowStr::new_static(
541 "Alt text description of the video, for accessibility.",
542 ),
543 ),
544 max_length: Some(10000usize),
545 max_graphemes: Some(1000usize),
546 ..Default::default()
547 }),
548 );
549 map.insert(
550 SmolStr::new_static("captions"),
551 LexObjectProperty::Array(LexArray {
552 items: LexArrayItem::Ref(LexRef {
553 r#ref: CowStr::new_static("#caption"),
554 ..Default::default()
555 }),
556 max_length: Some(20usize),
557 ..Default::default()
558 }),
559 );
560 map.insert(
561 SmolStr::new_static("dimensions"),
562 LexObjectProperty::Union(LexRefUnion {
563 refs: vec![
564 CowStr::new_static("app.bsky.embed.defs#aspectRatio"),
565 CowStr::new_static("sh.weaver.embed.defs#percentSize"),
566 CowStr::new_static("sh.weaver.embed.defs#pixelSize")
567 ],
568 ..Default::default()
569 }),
570 );
571 map.insert(
572 SmolStr::new_static("name"),
573 LexObjectProperty::String(LexString {
574 max_length: Some(128usize),
575 ..Default::default()
576 }),
577 );
578 map.insert(
579 SmolStr::new_static("video"),
580 LexObjectProperty::Blob(LexBlob { ..Default::default() }),
581 );
582 map
583 },
584 ..Default::default()
585 }),
586 );
587 map.insert(
588 SmolStr::new_static("view"),
589 LexUserType::Object(LexObject {
590 required: Some(
591 vec![SmolStr::new_static("cid"), SmolStr::new_static("playlist")],
592 ),
593 properties: {
594 #[allow(unused_mut)]
595 let mut map = BTreeMap::new();
596 map.insert(
597 SmolStr::new_static("alt"),
598 LexObjectProperty::String(LexString {
599 max_length: Some(10000usize),
600 max_graphemes: Some(1000usize),
601 ..Default::default()
602 }),
603 );
604 map.insert(
605 SmolStr::new_static("cid"),
606 LexObjectProperty::String(LexString {
607 format: Some(LexStringFormat::Cid),
608 ..Default::default()
609 }),
610 );
611 map.insert(
612 SmolStr::new_static("dimensions"),
613 LexObjectProperty::Union(LexRefUnion {
614 refs: vec![
615 CowStr::new_static("app.bsky.embed.defs#aspectRatio"),
616 CowStr::new_static("sh.weaver.embed.defs#percentSize"),
617 CowStr::new_static("sh.weaver.embed.defs#pixelSize")
618 ],
619 ..Default::default()
620 }),
621 );
622 map.insert(
623 SmolStr::new_static("name"),
624 LexObjectProperty::String(LexString {
625 max_length: Some(128usize),
626 ..Default::default()
627 }),
628 );
629 map.insert(
630 SmolStr::new_static("playlist"),
631 LexObjectProperty::String(LexString {
632 format: Some(LexStringFormat::Uri),
633 ..Default::default()
634 }),
635 );
636 map.insert(
637 SmolStr::new_static("thumbnail"),
638 LexObjectProperty::String(LexString {
639 format: Some(LexStringFormat::Uri),
640 ..Default::default()
641 }),
642 );
643 map
644 },
645 ..Default::default()
646 }),
647 );
648 map
649 },
650 ..Default::default()
651 }
652}
653
654pub mod video_record_state {
655
656 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
657 #[allow(unused)]
658 use ::core::marker::PhantomData;
659 mod sealed {
660 pub trait Sealed {}
661 }
662 pub trait State: sealed::Sealed {
664 type Videos;
665 }
666 pub struct Empty(());
668 impl sealed::Sealed for Empty {}
669 impl State for Empty {
670 type Videos = Unset;
671 }
672 pub struct SetVideos<S: State = Empty>(PhantomData<fn() -> S>);
674 impl<S: State> sealed::Sealed for SetVideos<S> {}
675 impl<S: State> State for SetVideos<S> {
676 type Videos = Set<members::videos>;
677 }
678 #[allow(non_camel_case_types)]
680 pub mod members {
681 pub struct videos(());
683 }
684}
685
686pub struct VideoRecordBuilder<'a, S: video_record_state::State> {
688 _state: PhantomData<fn() -> S>,
689 _fields: (Option<Vec<video::Video<'a>>>,),
690 _lifetime: PhantomData<&'a ()>,
691}
692
693impl<'a> VideoRecord<'a> {
694 pub fn new() -> VideoRecordBuilder<'a, video_record_state::Empty> {
696 VideoRecordBuilder::new()
697 }
698}
699
700impl<'a> VideoRecordBuilder<'a, video_record_state::Empty> {
701 pub fn new() -> Self {
703 VideoRecordBuilder {
704 _state: PhantomData,
705 _fields: (None,),
706 _lifetime: PhantomData,
707 }
708 }
709}
710
711impl<'a, S> VideoRecordBuilder<'a, S>
712where
713 S: video_record_state::State,
714 S::Videos: video_record_state::IsUnset,
715{
716 pub fn videos(
718 mut self,
719 value: impl Into<Vec<video::Video<'a>>>,
720 ) -> VideoRecordBuilder<'a, video_record_state::SetVideos<S>> {
721 self._fields.0 = Option::Some(value.into());
722 VideoRecordBuilder {
723 _state: PhantomData,
724 _fields: self._fields,
725 _lifetime: PhantomData,
726 }
727 }
728}
729
730impl<'a, S> VideoRecordBuilder<'a, S>
731where
732 S: video_record_state::State,
733 S::Videos: video_record_state::IsSet,
734{
735 pub fn build(self) -> VideoRecord<'a> {
737 VideoRecord {
738 videos: self._fields.0.unwrap(),
739 extra_data: Default::default(),
740 }
741 }
742 pub fn build_with_data(
744 self,
745 extra_data: BTreeMap<
746 jacquard_common::deps::smol_str::SmolStr,
747 jacquard_common::types::value::Data<'a>,
748 >,
749 ) -> VideoRecord<'a> {
750 VideoRecord {
751 videos: self._fields.0.unwrap(),
752 extra_data: Some(extra_data),
753 }
754 }
755}
756
757pub mod video_state {
758
759 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
760 #[allow(unused)]
761 use ::core::marker::PhantomData;
762 mod sealed {
763 pub trait Sealed {}
764 }
765 pub trait State: sealed::Sealed {
767 type Video;
768 }
769 pub struct Empty(());
771 impl sealed::Sealed for Empty {}
772 impl State for Empty {
773 type Video = Unset;
774 }
775 pub struct SetVideo<S: State = Empty>(PhantomData<fn() -> S>);
777 impl<S: State> sealed::Sealed for SetVideo<S> {}
778 impl<S: State> State for SetVideo<S> {
779 type Video = Set<members::video>;
780 }
781 #[allow(non_camel_case_types)]
783 pub mod members {
784 pub struct video(());
786 }
787}
788
789pub struct VideoBuilder<'a, S: video_state::State> {
791 _state: PhantomData<fn() -> S>,
792 _fields: (
793 Option<CowStr<'a>>,
794 Option<Vec<video::Caption<'a>>>,
795 Option<VideoDimensions<'a>>,
796 Option<CowStr<'a>>,
797 Option<BlobRef<'a>>,
798 ),
799 _lifetime: PhantomData<&'a ()>,
800}
801
802impl<'a> Video<'a> {
803 pub fn new() -> VideoBuilder<'a, video_state::Empty> {
805 VideoBuilder::new()
806 }
807}
808
809impl<'a> VideoBuilder<'a, video_state::Empty> {
810 pub fn new() -> Self {
812 VideoBuilder {
813 _state: PhantomData,
814 _fields: (None, None, None, None, None),
815 _lifetime: PhantomData,
816 }
817 }
818}
819
820impl<'a, S: video_state::State> VideoBuilder<'a, S> {
821 pub fn alt(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
823 self._fields.0 = value.into();
824 self
825 }
826 pub fn maybe_alt(mut self, value: Option<CowStr<'a>>) -> Self {
828 self._fields.0 = value;
829 self
830 }
831}
832
833impl<'a, S: video_state::State> VideoBuilder<'a, S> {
834 pub fn captions(
836 mut self,
837 value: impl Into<Option<Vec<video::Caption<'a>>>>,
838 ) -> Self {
839 self._fields.1 = value.into();
840 self
841 }
842 pub fn maybe_captions(mut self, value: Option<Vec<video::Caption<'a>>>) -> Self {
844 self._fields.1 = value;
845 self
846 }
847}
848
849impl<'a, S: video_state::State> VideoBuilder<'a, S> {
850 pub fn dimensions(mut self, value: impl Into<Option<VideoDimensions<'a>>>) -> Self {
852 self._fields.2 = value.into();
853 self
854 }
855 pub fn maybe_dimensions(mut self, value: Option<VideoDimensions<'a>>) -> Self {
857 self._fields.2 = value;
858 self
859 }
860}
861
862impl<'a, S: video_state::State> VideoBuilder<'a, S> {
863 pub fn name(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
865 self._fields.3 = value.into();
866 self
867 }
868 pub fn maybe_name(mut self, value: Option<CowStr<'a>>) -> Self {
870 self._fields.3 = value;
871 self
872 }
873}
874
875impl<'a, S> VideoBuilder<'a, S>
876where
877 S: video_state::State,
878 S::Video: video_state::IsUnset,
879{
880 pub fn video(
882 mut self,
883 value: impl Into<BlobRef<'a>>,
884 ) -> VideoBuilder<'a, video_state::SetVideo<S>> {
885 self._fields.4 = Option::Some(value.into());
886 VideoBuilder {
887 _state: PhantomData,
888 _fields: self._fields,
889 _lifetime: PhantomData,
890 }
891 }
892}
893
894impl<'a, S> VideoBuilder<'a, S>
895where
896 S: video_state::State,
897 S::Video: video_state::IsSet,
898{
899 pub fn build(self) -> Video<'a> {
901 Video {
902 alt: self._fields.0,
903 captions: self._fields.1,
904 dimensions: self._fields.2,
905 name: self._fields.3,
906 video: self._fields.4.unwrap(),
907 extra_data: Default::default(),
908 }
909 }
910 pub fn build_with_data(
912 self,
913 extra_data: BTreeMap<
914 jacquard_common::deps::smol_str::SmolStr,
915 jacquard_common::types::value::Data<'a>,
916 >,
917 ) -> Video<'a> {
918 Video {
919 alt: self._fields.0,
920 captions: self._fields.1,
921 dimensions: self._fields.2,
922 name: self._fields.3,
923 video: self._fields.4.unwrap(),
924 extra_data: Some(extra_data),
925 }
926 }
927}
928
929pub mod view_state {
930
931 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
932 #[allow(unused)]
933 use ::core::marker::PhantomData;
934 mod sealed {
935 pub trait Sealed {}
936 }
937 pub trait State: sealed::Sealed {
939 type Cid;
940 type Playlist;
941 }
942 pub struct Empty(());
944 impl sealed::Sealed for Empty {}
945 impl State for Empty {
946 type Cid = Unset;
947 type Playlist = Unset;
948 }
949 pub struct SetCid<S: State = Empty>(PhantomData<fn() -> S>);
951 impl<S: State> sealed::Sealed for SetCid<S> {}
952 impl<S: State> State for SetCid<S> {
953 type Cid = Set<members::cid>;
954 type Playlist = S::Playlist;
955 }
956 pub struct SetPlaylist<S: State = Empty>(PhantomData<fn() -> S>);
958 impl<S: State> sealed::Sealed for SetPlaylist<S> {}
959 impl<S: State> State for SetPlaylist<S> {
960 type Cid = S::Cid;
961 type Playlist = Set<members::playlist>;
962 }
963 #[allow(non_camel_case_types)]
965 pub mod members {
966 pub struct cid(());
968 pub struct playlist(());
970 }
971}
972
973pub struct ViewBuilder<'a, S: view_state::State> {
975 _state: PhantomData<fn() -> S>,
976 _fields: (
977 Option<CowStr<'a>>,
978 Option<Cid<'a>>,
979 Option<ViewDimensions<'a>>,
980 Option<CowStr<'a>>,
981 Option<UriValue<'a>>,
982 Option<UriValue<'a>>,
983 ),
984 _lifetime: PhantomData<&'a ()>,
985}
986
987impl<'a> View<'a> {
988 pub fn new() -> ViewBuilder<'a, view_state::Empty> {
990 ViewBuilder::new()
991 }
992}
993
994impl<'a> ViewBuilder<'a, view_state::Empty> {
995 pub fn new() -> Self {
997 ViewBuilder {
998 _state: PhantomData,
999 _fields: (None, None, None, None, None, None),
1000 _lifetime: PhantomData,
1001 }
1002 }
1003}
1004
1005impl<'a, S: view_state::State> ViewBuilder<'a, S> {
1006 pub fn alt(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
1008 self._fields.0 = value.into();
1009 self
1010 }
1011 pub fn maybe_alt(mut self, value: Option<CowStr<'a>>) -> Self {
1013 self._fields.0 = value;
1014 self
1015 }
1016}
1017
1018impl<'a, S> ViewBuilder<'a, S>
1019where
1020 S: view_state::State,
1021 S::Cid: view_state::IsUnset,
1022{
1023 pub fn cid(
1025 mut self,
1026 value: impl Into<Cid<'a>>,
1027 ) -> ViewBuilder<'a, view_state::SetCid<S>> {
1028 self._fields.1 = Option::Some(value.into());
1029 ViewBuilder {
1030 _state: PhantomData,
1031 _fields: self._fields,
1032 _lifetime: PhantomData,
1033 }
1034 }
1035}
1036
1037impl<'a, S: view_state::State> ViewBuilder<'a, S> {
1038 pub fn dimensions(mut self, value: impl Into<Option<ViewDimensions<'a>>>) -> Self {
1040 self._fields.2 = value.into();
1041 self
1042 }
1043 pub fn maybe_dimensions(mut self, value: Option<ViewDimensions<'a>>) -> Self {
1045 self._fields.2 = value;
1046 self
1047 }
1048}
1049
1050impl<'a, S: view_state::State> ViewBuilder<'a, S> {
1051 pub fn name(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
1053 self._fields.3 = value.into();
1054 self
1055 }
1056 pub fn maybe_name(mut self, value: Option<CowStr<'a>>) -> Self {
1058 self._fields.3 = value;
1059 self
1060 }
1061}
1062
1063impl<'a, S> ViewBuilder<'a, S>
1064where
1065 S: view_state::State,
1066 S::Playlist: view_state::IsUnset,
1067{
1068 pub fn playlist(
1070 mut self,
1071 value: impl Into<UriValue<'a>>,
1072 ) -> ViewBuilder<'a, view_state::SetPlaylist<S>> {
1073 self._fields.4 = Option::Some(value.into());
1074 ViewBuilder {
1075 _state: PhantomData,
1076 _fields: self._fields,
1077 _lifetime: PhantomData,
1078 }
1079 }
1080}
1081
1082impl<'a, S: view_state::State> ViewBuilder<'a, S> {
1083 pub fn thumbnail(mut self, value: impl Into<Option<UriValue<'a>>>) -> Self {
1085 self._fields.5 = value.into();
1086 self
1087 }
1088 pub fn maybe_thumbnail(mut self, value: Option<UriValue<'a>>) -> Self {
1090 self._fields.5 = value;
1091 self
1092 }
1093}
1094
1095impl<'a, S> ViewBuilder<'a, S>
1096where
1097 S: view_state::State,
1098 S::Cid: view_state::IsSet,
1099 S::Playlist: view_state::IsSet,
1100{
1101 pub fn build(self) -> View<'a> {
1103 View {
1104 alt: self._fields.0,
1105 cid: self._fields.1.unwrap(),
1106 dimensions: self._fields.2,
1107 name: self._fields.3,
1108 playlist: self._fields.4.unwrap(),
1109 thumbnail: self._fields.5,
1110 extra_data: Default::default(),
1111 }
1112 }
1113 pub fn build_with_data(
1115 self,
1116 extra_data: BTreeMap<
1117 jacquard_common::deps::smol_str::SmolStr,
1118 jacquard_common::types::value::Data<'a>,
1119 >,
1120 ) -> View<'a> {
1121 View {
1122 alt: self._fields.0,
1123 cid: self._fields.1.unwrap(),
1124 dimensions: self._fields.2,
1125 name: self._fields.3,
1126 playlist: self._fields.4.unwrap(),
1127 thumbnail: self._fields.5,
1128 extra_data: Some(extra_data),
1129 }
1130 }
1131}