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_derive::{IntoStatic, lexicon};
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::pub_leaflet::blocks::image;
26
27#[lexicon]
28#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
29#[serde(rename_all = "camelCase")]
30pub struct AspectRatio<'a> {
31 pub height: i64,
32 pub width: i64,
33}
34
35
36#[lexicon]
37#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
38#[serde(rename_all = "camelCase")]
39pub struct Image<'a> {
40 #[serde(skip_serializing_if = "Option::is_none")]
42 #[serde(borrow)]
43 pub alt: Option<CowStr<'a>>,
44 #[serde(borrow)]
45 pub aspect_ratio: image::AspectRatio<'a>,
46 #[serde(borrow)]
47 pub image: BlobRef<'a>,
48}
49
50impl<'a> LexiconSchema for AspectRatio<'a> {
51 fn nsid() -> &'static str {
52 "pub.leaflet.blocks.image"
53 }
54 fn def_name() -> &'static str {
55 "aspectRatio"
56 }
57 fn lexicon_doc() -> LexiconDoc<'static> {
58 lexicon_doc_pub_leaflet_blocks_image()
59 }
60 fn validate(&self) -> Result<(), ConstraintError> {
61 Ok(())
62 }
63}
64
65impl<'a> LexiconSchema for Image<'a> {
66 fn nsid() -> &'static str {
67 "pub.leaflet.blocks.image"
68 }
69 fn def_name() -> &'static str {
70 "main"
71 }
72 fn lexicon_doc() -> LexiconDoc<'static> {
73 lexicon_doc_pub_leaflet_blocks_image()
74 }
75 fn validate(&self) -> Result<(), ConstraintError> {
76 {
77 let value = &self.image;
78 {
79 let size = value.blob().size;
80 if size > 1000000usize {
81 return Err(ConstraintError::BlobTooLarge {
82 path: ValidationPath::from_field("image"),
83 max: 1000000usize,
84 actual: size,
85 });
86 }
87 }
88 }
89 {
90 let value = &self.image;
91 {
92 let mime = value.blob().mime_type.as_str();
93 let accepted: &[&str] = &["image/*"];
94 let matched = accepted
95 .iter()
96 .any(|pattern| {
97 if *pattern == "*/*" {
98 true
99 } else if pattern.ends_with("/*") {
100 let prefix = &pattern[..pattern.len() - 2];
101 mime.starts_with(prefix)
102 && mime.as_bytes().get(prefix.len()) == Some(&b'/')
103 } else {
104 mime == *pattern
105 }
106 });
107 if !matched {
108 return Err(ConstraintError::BlobMimeTypeNotAccepted {
109 path: ValidationPath::from_field("image"),
110 accepted: vec!["image/*".to_string()],
111 actual: mime.to_string(),
112 });
113 }
114 }
115 }
116 Ok(())
117 }
118}
119
120pub mod aspect_ratio_state {
121
122 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
123 #[allow(unused)]
124 use ::core::marker::PhantomData;
125 mod sealed {
126 pub trait Sealed {}
127 }
128 pub trait State: sealed::Sealed {
130 type Height;
131 type Width;
132 }
133 pub struct Empty(());
135 impl sealed::Sealed for Empty {}
136 impl State for Empty {
137 type Height = Unset;
138 type Width = Unset;
139 }
140 pub struct SetHeight<S: State = Empty>(PhantomData<fn() -> S>);
142 impl<S: State> sealed::Sealed for SetHeight<S> {}
143 impl<S: State> State for SetHeight<S> {
144 type Height = Set<members::height>;
145 type Width = S::Width;
146 }
147 pub struct SetWidth<S: State = Empty>(PhantomData<fn() -> S>);
149 impl<S: State> sealed::Sealed for SetWidth<S> {}
150 impl<S: State> State for SetWidth<S> {
151 type Height = S::Height;
152 type Width = Set<members::width>;
153 }
154 #[allow(non_camel_case_types)]
156 pub mod members {
157 pub struct height(());
159 pub struct width(());
161 }
162}
163
164pub struct AspectRatioBuilder<'a, S: aspect_ratio_state::State> {
166 _state: PhantomData<fn() -> S>,
167 _fields: (Option<i64>, Option<i64>),
168 _lifetime: PhantomData<&'a ()>,
169}
170
171impl<'a> AspectRatio<'a> {
172 pub fn new() -> AspectRatioBuilder<'a, aspect_ratio_state::Empty> {
174 AspectRatioBuilder::new()
175 }
176}
177
178impl<'a> AspectRatioBuilder<'a, aspect_ratio_state::Empty> {
179 pub fn new() -> Self {
181 AspectRatioBuilder {
182 _state: PhantomData,
183 _fields: (None, None),
184 _lifetime: PhantomData,
185 }
186 }
187}
188
189impl<'a, S> AspectRatioBuilder<'a, S>
190where
191 S: aspect_ratio_state::State,
192 S::Height: aspect_ratio_state::IsUnset,
193{
194 pub fn height(
196 mut self,
197 value: impl Into<i64>,
198 ) -> AspectRatioBuilder<'a, aspect_ratio_state::SetHeight<S>> {
199 self._fields.0 = Option::Some(value.into());
200 AspectRatioBuilder {
201 _state: PhantomData,
202 _fields: self._fields,
203 _lifetime: PhantomData,
204 }
205 }
206}
207
208impl<'a, S> AspectRatioBuilder<'a, S>
209where
210 S: aspect_ratio_state::State,
211 S::Width: aspect_ratio_state::IsUnset,
212{
213 pub fn width(
215 mut self,
216 value: impl Into<i64>,
217 ) -> AspectRatioBuilder<'a, aspect_ratio_state::SetWidth<S>> {
218 self._fields.1 = Option::Some(value.into());
219 AspectRatioBuilder {
220 _state: PhantomData,
221 _fields: self._fields,
222 _lifetime: PhantomData,
223 }
224 }
225}
226
227impl<'a, S> AspectRatioBuilder<'a, S>
228where
229 S: aspect_ratio_state::State,
230 S::Height: aspect_ratio_state::IsSet,
231 S::Width: aspect_ratio_state::IsSet,
232{
233 pub fn build(self) -> AspectRatio<'a> {
235 AspectRatio {
236 height: self._fields.0.unwrap(),
237 width: self._fields.1.unwrap(),
238 extra_data: Default::default(),
239 }
240 }
241 pub fn build_with_data(
243 self,
244 extra_data: BTreeMap<
245 jacquard_common::deps::smol_str::SmolStr,
246 jacquard_common::types::value::Data<'a>,
247 >,
248 ) -> AspectRatio<'a> {
249 AspectRatio {
250 height: self._fields.0.unwrap(),
251 width: self._fields.1.unwrap(),
252 extra_data: Some(extra_data),
253 }
254 }
255}
256
257fn lexicon_doc_pub_leaflet_blocks_image() -> LexiconDoc<'static> {
258 #[allow(unused_imports)]
259 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
260 use jacquard_lexicon::lexicon::*;
261 use alloc::collections::BTreeMap;
262 LexiconDoc {
263 lexicon: Lexicon::Lexicon1,
264 id: CowStr::new_static("pub.leaflet.blocks.image"),
265 defs: {
266 let mut map = BTreeMap::new();
267 map.insert(
268 SmolStr::new_static("aspectRatio"),
269 LexUserType::Object(LexObject {
270 required: Some(
271 vec![SmolStr::new_static("width"), SmolStr::new_static("height")],
272 ),
273 properties: {
274 #[allow(unused_mut)]
275 let mut map = BTreeMap::new();
276 map.insert(
277 SmolStr::new_static("height"),
278 LexObjectProperty::Integer(LexInteger {
279 ..Default::default()
280 }),
281 );
282 map.insert(
283 SmolStr::new_static("width"),
284 LexObjectProperty::Integer(LexInteger {
285 ..Default::default()
286 }),
287 );
288 map
289 },
290 ..Default::default()
291 }),
292 );
293 map.insert(
294 SmolStr::new_static("main"),
295 LexUserType::Object(LexObject {
296 required: Some(
297 vec![
298 SmolStr::new_static("image"),
299 SmolStr::new_static("aspectRatio")
300 ],
301 ),
302 properties: {
303 #[allow(unused_mut)]
304 let mut map = BTreeMap::new();
305 map.insert(
306 SmolStr::new_static("alt"),
307 LexObjectProperty::String(LexString {
308 description: Some(
309 CowStr::new_static(
310 "Alt text description of the image, for accessibility.",
311 ),
312 ),
313 ..Default::default()
314 }),
315 );
316 map.insert(
317 SmolStr::new_static("aspectRatio"),
318 LexObjectProperty::Ref(LexRef {
319 r#ref: CowStr::new_static("#aspectRatio"),
320 ..Default::default()
321 }),
322 );
323 map.insert(
324 SmolStr::new_static("image"),
325 LexObjectProperty::Blob(LexBlob { ..Default::default() }),
326 );
327 map
328 },
329 ..Default::default()
330 }),
331 );
332 map
333 },
334 ..Default::default()
335 }
336}
337
338pub mod image_state {
339
340 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
341 #[allow(unused)]
342 use ::core::marker::PhantomData;
343 mod sealed {
344 pub trait Sealed {}
345 }
346 pub trait State: sealed::Sealed {
348 type AspectRatio;
349 type Image;
350 }
351 pub struct Empty(());
353 impl sealed::Sealed for Empty {}
354 impl State for Empty {
355 type AspectRatio = Unset;
356 type Image = Unset;
357 }
358 pub struct SetAspectRatio<S: State = Empty>(PhantomData<fn() -> S>);
360 impl<S: State> sealed::Sealed for SetAspectRatio<S> {}
361 impl<S: State> State for SetAspectRatio<S> {
362 type AspectRatio = Set<members::aspect_ratio>;
363 type Image = S::Image;
364 }
365 pub struct SetImage<S: State = Empty>(PhantomData<fn() -> S>);
367 impl<S: State> sealed::Sealed for SetImage<S> {}
368 impl<S: State> State for SetImage<S> {
369 type AspectRatio = S::AspectRatio;
370 type Image = Set<members::image>;
371 }
372 #[allow(non_camel_case_types)]
374 pub mod members {
375 pub struct aspect_ratio(());
377 pub struct image(());
379 }
380}
381
382pub struct ImageBuilder<'a, S: image_state::State> {
384 _state: PhantomData<fn() -> S>,
385 _fields: (Option<CowStr<'a>>, Option<image::AspectRatio<'a>>, Option<BlobRef<'a>>),
386 _lifetime: PhantomData<&'a ()>,
387}
388
389impl<'a> Image<'a> {
390 pub fn new() -> ImageBuilder<'a, image_state::Empty> {
392 ImageBuilder::new()
393 }
394}
395
396impl<'a> ImageBuilder<'a, image_state::Empty> {
397 pub fn new() -> Self {
399 ImageBuilder {
400 _state: PhantomData,
401 _fields: (None, None, None),
402 _lifetime: PhantomData,
403 }
404 }
405}
406
407impl<'a, S: image_state::State> ImageBuilder<'a, S> {
408 pub fn alt(mut self, value: impl Into<Option<CowStr<'a>>>) -> Self {
410 self._fields.0 = value.into();
411 self
412 }
413 pub fn maybe_alt(mut self, value: Option<CowStr<'a>>) -> Self {
415 self._fields.0 = value;
416 self
417 }
418}
419
420impl<'a, S> ImageBuilder<'a, S>
421where
422 S: image_state::State,
423 S::AspectRatio: image_state::IsUnset,
424{
425 pub fn aspect_ratio(
427 mut self,
428 value: impl Into<image::AspectRatio<'a>>,
429 ) -> ImageBuilder<'a, image_state::SetAspectRatio<S>> {
430 self._fields.1 = Option::Some(value.into());
431 ImageBuilder {
432 _state: PhantomData,
433 _fields: self._fields,
434 _lifetime: PhantomData,
435 }
436 }
437}
438
439impl<'a, S> ImageBuilder<'a, S>
440where
441 S: image_state::State,
442 S::Image: image_state::IsUnset,
443{
444 pub fn image(
446 mut self,
447 value: impl Into<BlobRef<'a>>,
448 ) -> ImageBuilder<'a, image_state::SetImage<S>> {
449 self._fields.2 = Option::Some(value.into());
450 ImageBuilder {
451 _state: PhantomData,
452 _fields: self._fields,
453 _lifetime: PhantomData,
454 }
455 }
456}
457
458impl<'a, S> ImageBuilder<'a, S>
459where
460 S: image_state::State,
461 S::AspectRatio: image_state::IsSet,
462 S::Image: image_state::IsSet,
463{
464 pub fn build(self) -> Image<'a> {
466 Image {
467 alt: self._fields.0,
468 aspect_ratio: self._fields.1.unwrap(),
469 image: self._fields.2.unwrap(),
470 extra_data: Default::default(),
471 }
472 }
473 pub fn build_with_data(
475 self,
476 extra_data: BTreeMap<
477 jacquard_common::deps::smol_str::SmolStr,
478 jacquard_common::types::value::Data<'a>,
479 >,
480 ) -> Image<'a> {
481 Image {
482 alt: self._fields.0,
483 aspect_ratio: self._fields.1.unwrap(),
484 image: self._fields.2.unwrap(),
485 extra_data: Some(extra_data),
486 }
487 }
488}