wot_td/builder/
data_schema.rs

1//! The builder elements related to data schemas.
2//!
3//! The main entry point of the module is [`DataSchemaBuilder`], which can be _extended_ and
4//! _specialized_ in different ways.
5//!
6//! The extension mechanism is similar to other structures as shown in [`builder`] module, with the
7//! difference that `DataSchemaBuilder` *must* declare when the process is completed using the
8//! [`finish_extend`] method. The reason behind this is because the _specialization_ process (see
9//! below) requires the modification of specific elements of the builder, which could cause data
10//! loss in case of further extension or non-zero cost approaches to avoid the problem. In this
11//! way, it is not possible to _specialize_ the `DataSchemaBuilder` before all the extensions have
12//! been performed.
13//!
14//! The _specialization_ process involves the following traits:
15//!
16//! - [`SpecializableDataSchema`]
17//! - [`EnumerableDataSchema`]
18//! - [`UnionDataSchema`]
19//! - [`ReadableWriteableDataSchema`]
20//!
21//! The `SpecializableDataSchema` trait allows transforming a generic builder into a builder for a
22//! specific subtype, for instance using the `number()` function to obtain a _number data schema
23//! builder_. The trait is only implemented on generic builder types.
24//!
25//! The `EnumerableDataSchema` and `UnionDataSchema` traits are similar to
26//! `SpecializableDataSchema` in terms of specialization, but they are also implemented on
27//! specific specialized structs in order to allow adding more _variants_ to the enumeration/union.
28//!
29//! The `ReadableWriteableDataSchema` is an auxiliary trait that allows transforming a specialized builder
30//! into a read-only/write-only variant, keeping the existing behavior of the original one. However,
31//! [`ReadOnly`] and [`WriteOnly`] types do not implement `ReadableWriteableDataSchema`, which
32//! means that you cannot create a `DataSchema` with both [`read_only`] and [`write_only`] fields
33//! set to true using the builder.
34//!
35//! Any `DataSchema` builder also implements [`BuildableHumanReadableInfo`] and
36//! [`BuildableDataSchema`], in order to customize _common_ fields.
37//!
38//! [`builder`]: crate::builder
39//! [`finish_extend`]: DataSchemaBuilder::finish_extend
40//! [`read_only`]: crate::thing::DataSchema::read_only
41//! [`write_only`]: crate::thing::DataSchema::write_only
42use alloc::{boxed::Box, string::String, vec::Vec};
43use core::{cmp::Ordering, marker::PhantomData, num::NonZeroU64, ops::Not};
44
45use hashbrown::HashMap;
46
47use crate::{
48    extend::{Extend, Extendable, ExtendableThing},
49    thing::{
50        ArraySchema, BoxedElemOrVec, DataSchema, DataSchemaSubtype, IntegerSchema, Maximum,
51        Minimum, NumberSchema, ObjectSchema, StringSchema, UncheckedArraySchema,
52        UncheckedDataSchemaSubtype, UncheckedObjectSchema,
53    },
54};
55
56use super::{
57    human_readable_info::{
58        impl_delegate_buildable_hr_info, BuildableHumanReadableInfo, HumanReadableInfo,
59    },
60    Error, Extended, MultiLanguageBuilder, ToExtend,
61};
62
63/// The _unchecked_ variant of a [`DataSchema`](crate::thing::DataSchema).
64///
65/// This can be transformed into a valid `DataSchema` by
66/// [`ThingBuilder::build`](crate::builder::ThingBuilder::build).
67#[derive(Clone, Debug, Default, PartialEq)]
68pub struct UncheckedDataSchema<DS, AS, OS> {
69    attype: Option<Vec<String>>,
70    title: Option<String>,
71    titles: Option<MultiLanguageBuilder<String>>,
72    description: Option<String>,
73    descriptions: Option<MultiLanguageBuilder<String>>,
74    constant: Option<Value>,
75    default: Option<Value>,
76    unit: Option<String>,
77    one_of: Option<Vec<Self>>,
78    enumeration: Option<Vec<Value>>,
79    read_only: bool,
80    write_only: bool,
81    format: Option<String>,
82    subtype: Option<UncheckedDataSchemaSubtype<DS, AS, OS>>,
83    other: DS,
84}
85
86pub(crate) type UncheckedDataSchemaFromOther<Other> = UncheckedDataSchema<
87    <Other as ExtendableThing>::DataSchema,
88    <Other as ExtendableThing>::ArraySchema,
89    <Other as ExtendableThing>::ObjectSchema,
90>;
91
92pub(crate) type UncheckedDataSchemaMap<Other> = HashMap<
93    String,
94    UncheckedDataSchema<
95        <Other as ExtendableThing>::DataSchema,
96        <Other as ExtendableThing>::ArraySchema,
97        <Other as ExtendableThing>::ObjectSchema,
98    >,
99>;
100
101/// _Partial_ variant of a [`DataSchemaBuilder`].
102///
103/// This variant is necessary for building a [`PropertyAffordance`], which is composed of a set of
104/// _human readable_ fields shared between [`InteractionAffordance`] and [`DataSchema`].
105///
106/// This builder behaves like a [`DataSchemaBuilder`] that does not implement
107/// [`BuildableHumanReadableInfo`].
108///
109/// [`PropertyAffordance`]: crate::thing::PropertyAffordance
110/// [`InteractionAffordance`]: crate::thing::InteractionAffordance
111#[derive(Debug, PartialEq)]
112pub struct PartialDataSchemaBuilder<DS, AS, OS, Status> {
113    constant: Option<Value>,
114    default: Option<Value>,
115    unit: Option<String>,
116    one_of: Vec<UncheckedDataSchema<DS, AS, OS>>,
117    enumeration: Vec<Value>,
118    read_only: bool,
119    write_only: bool,
120    format: Option<String>,
121
122    /// Data schema extension.
123    pub other: DS,
124    _marker: PhantomData<Status>,
125}
126
127impl<DS, AS, OS> PartialDataSchemaBuilder<DS, AS, OS, ToExtend> {
128    pub(crate) fn empty() -> PartialDataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>
129    where
130        DS: Extendable,
131    {
132        PartialDataSchemaBuilder {
133            constant: Default::default(),
134            default: Default::default(),
135            unit: Default::default(),
136            one_of: Default::default(),
137            enumeration: Default::default(),
138            read_only: Default::default(),
139            write_only: Default::default(),
140            format: Default::default(),
141            other: DS::empty(),
142            _marker: PhantomData,
143        }
144    }
145}
146
147impl<DS, AS, OS> PartialDataSchemaBuilder<DS, AS, OS, ToExtend> {
148    /// Extends the data schema, passing a closure that returns `T`.
149    pub fn ext_with<F, T>(self, f: F) -> PartialDataSchemaBuilder<DS::Target, AS, OS, ToExtend>
150    where
151        F: FnOnce() -> T,
152        DS: Extend<T>,
153    {
154        let Self {
155            constant,
156            default,
157            unit,
158            one_of: _,
159            enumeration,
160            read_only,
161            write_only,
162            format,
163            other,
164            _marker,
165        } = self;
166        let other = other.ext_with(f);
167        PartialDataSchemaBuilder {
168            constant,
169            default,
170            unit,
171            one_of: Default::default(),
172            enumeration,
173            read_only,
174            write_only,
175            format,
176            other,
177            _marker,
178        }
179    }
180
181    /// Extends the data schema with an additional element.
182    #[inline]
183    pub fn ext<T>(self, t: T) -> PartialDataSchemaBuilder<DS::Target, AS, OS, ToExtend>
184    where
185        DS: Extend<T>,
186    {
187        self.ext_with(|| t)
188    }
189
190    /// Makes the builder unextendable and allows further customizations.
191    pub fn finish_extend(self) -> PartialDataSchemaBuilder<DS, AS, OS, Extended> {
192        let Self {
193            constant,
194            default,
195            unit,
196            one_of,
197            enumeration,
198            read_only,
199            write_only,
200            format,
201            other,
202            _marker: _,
203        } = self;
204        PartialDataSchemaBuilder {
205            constant,
206            default,
207            unit,
208            one_of,
209            enumeration,
210            read_only,
211            write_only,
212            format,
213            other,
214            _marker: PhantomData,
215        }
216    }
217}
218
219impl<DS, AS, OS> Default for PartialDataSchemaBuilder<DS, AS, OS, Extended>
220where
221    DS: Default,
222{
223    fn default() -> Self {
224        Self {
225            constant: Default::default(),
226            default: Default::default(),
227            unit: Default::default(),
228            one_of: Default::default(),
229            enumeration: Default::default(),
230            read_only: Default::default(),
231            write_only: Default::default(),
232            format: Default::default(),
233            other: Default::default(),
234            _marker: Default::default(),
235        }
236    }
237}
238
239/// _Partial_ variant of a [`DataSchema`].
240///
241/// This variant does not include the _human readable_ fields. It is always converted into the
242/// complete `DataSchema` structure during the _building_ process.
243#[derive(Debug, Default, PartialEq)]
244pub struct PartialDataSchema<DS, AS, OS> {
245    pub(super) constant: Option<Value>,
246    pub(super) default: Option<Value>,
247    pub(super) unit: Option<String>,
248    pub(super) one_of: Option<Vec<UncheckedDataSchema<DS, AS, OS>>>,
249    pub(super) enumeration: Option<Vec<Value>>,
250    pub(super) read_only: bool,
251    pub(super) write_only: bool,
252    pub(super) format: Option<String>,
253    pub(super) subtype: Option<UncheckedDataSchemaSubtype<DS, AS, OS>>,
254
255    /// Data schema extension.
256    pub other: DS,
257}
258
259/// Basic builder for [`DataSchema`].
260///
261/// This is builder must be both _extended_ and _specialized_, see the [module documentation] for
262/// a general overview of the concepts.
263///
264/// `DataSchemaBuilder` implements `[BuildableHumanReadableInfo]` in order to customize _human
265/// readable_ fields, but it is not directly convertible into a
266/// `DataSchema`/`UncheckedDataSchema`. For instance, the following fails to compile:
267///
268/// ```compile_fail
269/// # use wot_td::{
270/// #     builder::data_schema::{DataSchemaBuilder, UncheckedDataSchema},
271/// #     hlist::Nil,
272/// # };
273/// #
274/// let data_schema: UncheckedDataSchema<Nil, Nil, Nil> = DataSchemaBuilder::default().into();
275/// ```
276///
277/// In order to correctly use `DataSchemaBuilder`, the following three steps are required:
278///
279/// 1. call [`ext`]/[`ext_with`] in order to add generic _data schema_ extensions as specified in
280///    the [`ThingBuilder`];
281/// 2. call [`finish_extend`];
282/// 3. _specialize_ the builder.
283///
284/// [module documentation]: self
285/// [`ext`]: Self::ext
286/// [`ext_with`]: Self::ext_with
287/// [`ThingBuilder`]: crate::builder::ThingBuilder
288/// [`finish_extend`]: Self::finish_extend
289///
290/// # Example
291/// ```
292/// # use serde::{Deserialize, Serialize};
293/// # use serde_json::json;
294/// # use wot_td::{
295/// #     builder::data_schema::SpecializableDataSchema, extend::ExtendableThing, thing::Thing,
296/// # };
297/// #
298/// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
299/// struct ThingExtension {}
300///
301/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
302/// struct DataExtension {
303///     data_schema_field: u32,
304/// }
305///
306/// impl ExtendableThing for ThingExtension {
307///     type DataSchema = DataExtension;
308///     /* Other types set to `()` */
309/// #   type Form = ();
310/// #   type InteractionAffordance = ();
311/// #   type PropertyAffordance = ();
312/// #   type ActionAffordance = ();
313/// #   type EventAffordance = ();
314/// #   type ExpectedResponse = ();
315/// #   type ObjectSchema = ();
316/// #   type ArraySchema = ();
317/// }
318///
319/// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
320/// struct DummyExtension {}
321///
322/// impl ExtendableThing for DummyExtension {
323///     /* Types set to `()` */
324/// #   type InteractionAffordance = ();
325/// #   type PropertyAffordance = ();
326/// #   type ActionAffordance = ();
327/// #   type EventAffordance = ();
328/// #   type Form = ();
329/// #   type ExpectedResponse = ();
330/// #   type DataSchema = ();
331/// #   type ObjectSchema = ();
332/// #   type ArraySchema = ();
333/// }
334///
335/// let thing = Thing::builder("Thing name")
336///     .ext(ThingExtension {})
337///     .ext(DummyExtension {})
338///     .finish_extend()
339///     .schema_definition("test", |b| {
340///         b.ext(DataExtension {
341///             data_schema_field: 42,
342///         })
343///         .ext(())
344///         .finish_extend()
345///         .number()
346///     })
347///     .build()
348///     .unwrap();
349///
350/// assert_eq!(
351///     serde_json::to_value(thing).unwrap(),
352///     json!({
353///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
354///         "title": "Thing name",
355///         "schemaDefinitions": {
356///             "test": {
357///                 "type": "number",
358///                 "data_schema_field": 42,
359///                 "readOnly": false,
360///                 "writeOnly": false,
361///             }
362///         },
363///         "security": [],
364///         "securityDefinitions": {},
365///     })
366/// );
367/// ```
368#[derive(Debug, PartialEq)]
369pub struct DataSchemaBuilder<DS, AS, OS, Status> {
370    partial: PartialDataSchemaBuilder<DS, AS, OS, Status>,
371    info: HumanReadableInfo,
372}
373
374impl<DS, AS, OS> DataSchemaBuilder<DS, AS, OS, ToExtend> {
375    /// Extends the data schema, passing a closure that returns `T`.
376    pub fn ext_with<F, T>(self, f: F) -> DataSchemaBuilder<DS::Target, AS, OS, ToExtend>
377    where
378        F: FnOnce() -> T,
379        DS: Extend<T>,
380    {
381        let Self { partial, info } = self;
382        let partial = partial.ext_with(f);
383        DataSchemaBuilder { partial, info }
384    }
385
386    /// Extends the data schema with an additional element.
387    #[inline]
388    pub fn ext<T>(self, t: T) -> DataSchemaBuilder<DS::Target, AS, OS, ToExtend>
389    where
390        DS: Extend<T>,
391    {
392        self.ext_with(|| t)
393    }
394
395    /// Makes the builder unextendable and allows further customizations.
396    pub fn finish_extend(self) -> DataSchemaBuilder<DS, AS, OS, Extended> {
397        let Self { partial, info } = self;
398        let partial = partial.finish_extend();
399        DataSchemaBuilder { partial, info }
400    }
401}
402
403impl<DS, AS, OS> DataSchemaBuilder<DS, AS, OS, ToExtend> {
404    pub(crate) fn empty() -> DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>
405    where
406        DS: Extendable,
407    {
408        DataSchemaBuilder {
409            partial: PartialDataSchemaBuilder::<DS, _, _, _>::empty(),
410            info: Default::default(),
411        }
412    }
413}
414
415impl<DS, AS, OS> Default for DataSchemaBuilder<DS, AS, OS, Extended>
416where
417    DS: Default,
418{
419    fn default() -> Self {
420        Self {
421            partial: Default::default(),
422            info: Default::default(),
423        }
424    }
425}
426
427/// An interface for a buildable version of a [`DataSchema`](crate::thing::DataSchema).
428///
429/// In order to model the specification, each type that can be created using a builder pattern and
430/// that _behaves_ like an `DataSchema` should implement this trait.
431///
432/// # Notes
433///
434/// This trait *should not* be implemented directly, even if it is not sealed.
435pub trait BuildableDataSchema<DS, AS, OS, Status>: Sized {
436    /// Sets the value of the `unit` field.
437    fn unit(self, value: impl Into<String>) -> Self;
438
439    /// Sets the value of the `format` field.
440    fn format(self, value: impl Into<String>) -> Self;
441
442    /// Sets the value of the `default` field.
443    fn default_value(self, value: impl Into<Value>) -> Self;
444}
445
446/// An interface for a _specializable_ version of a [`DataSchema`](crate::thing::DataSchema).
447///
448/// A meaningful `DataSchema` should always contain a valid
449/// [`subtype`](crate::thing::DataSchema::subtype) field, unless `enumeration` or `one_of` fields
450/// are used. This trait allows to safely transform an _unspecialized_ `DataSchema` into a
451/// _specialized_ one.
452///
453/// # Notes
454///
455/// - This trait *should not* be implemented directly, even if it is not sealed.
456/// - This is going to break in future releases in order to have less, more expressive code.
457pub trait SpecializableDataSchema<DS, AS, OS>: BuildableDataSchema<DS, AS, OS, Extended> {
458    /// A generic stateless specialized data schema builder.
459    type Stateless: BuildableDataSchema<DS, AS, OS, Extended>;
460
461    /// The _array_ specialization of the data schema builder, representing a tuple of items.
462    type Tuple: BuildableDataSchema<DS, AS, OS, Extended>;
463
464    /// The _array_ specialization of the data schema builder, representing an _homogeneous list_.
465    type Vec: BuildableDataSchema<DS, AS, OS, Extended>;
466
467    /// The _number_ specialization of the data schema builder.
468    type Number: BuildableDataSchema<DS, AS, OS, Extended>;
469
470    /// The _integer_ specialization of the data schema builder.
471    type Integer: BuildableDataSchema<DS, AS, OS, Extended>;
472
473    /// The _object_ specialization of the data schema builder.
474    type Object: BuildableDataSchema<DS, AS, OS, Extended>;
475
476    /// The _string_ specialization of the data schema builder.
477    type String: BuildableDataSchema<DS, AS, OS, Extended>;
478
479    /// The _constant_ specialization of the data schema builder.
480    type Constant: BuildableDataSchema<DS, AS, OS, Extended>;
481
482    /// Specialize the builder into an _array_ data schema builder representing a tuple,
483    /// initializing the array extensions with default values.
484    ///
485    /// Note that this function can only be called if `AS` implements [`Default`], use
486    /// [`tuple_ext`] otherwise.
487    ///
488    /// [`tuple_ext`]: Self::tuple_ext
489    ///
490    /// # Examples
491    /// ```
492    /// # use serde::{Deserialize, Serialize};
493    /// # use serde_json::json;
494    /// # use wot_td::{
495    /// #     builder::data_schema::SpecializableDataSchema, extend::ExtendableThing, thing::Thing,
496    /// # };
497    /// #
498    /// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
499    /// struct ThingExtension {}
500    ///
501    /// #[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
502    /// struct ArraySchemaExtension {
503    ///     array_field: u32,
504    /// }
505    ///
506    /// impl ExtendableThing for ThingExtension {
507    ///     type ArraySchema = ArraySchemaExtension;
508    ///     /* Other types set to `()` */
509    /// #   type Form = ();
510    /// #   type InteractionAffordance = ();
511    /// #   type PropertyAffordance = ();
512    /// #   type ActionAffordance = ();
513    /// #   type EventAffordance = ();
514    /// #   type ExpectedResponse = ();
515    /// #   type DataSchema = ();
516    /// #   type ObjectSchema = ();
517    /// }
518    ///
519    /// let thing = Thing::builder("Thing name")
520    ///     .ext(ThingExtension {})
521    ///     .finish_extend()
522    ///     .schema_definition("test", |b| b.ext(()).finish_extend().tuple())
523    ///     .build()
524    ///     .unwrap();
525    ///
526    /// assert_eq!(
527    ///     serde_json::to_value(thing).unwrap(),
528    ///     json!({
529    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
530    ///         "title": "Thing name",
531    ///         "schemaDefinitions": {
532    ///             "test": {
533    ///                 "type": "array",
534    ///                 "items": [],
535    ///                 "array_field": 0,
536    ///                 "readOnly": false,
537    ///                 "writeOnly": false,
538    ///             }
539    ///         },
540    ///         "security": [],
541    ///         "securityDefinitions": {},
542    ///     })
543    /// );
544    /// ```
545    ///
546    /// The following does not work instead:
547    ///
548    /// ```compile_fail
549    /// # use serde::{Deserialize, Serialize};
550    /// # use serde_json::json;
551    /// # use wot_td::{
552    /// #     builder::data_schema::SpecializableDataSchema, extend::ExtendableThing, thing::Thing,
553    /// # };
554    /// #
555    /// # #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
556    /// # struct ThingExtension {}
557    /// #
558    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
559    /// struct NotDefaultableU32(u32);
560    ///
561    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
562    /// struct ArraySchemaExtension {
563    ///     array_field: NotDefaultableU32,
564    /// }
565    ///
566    /// # impl ExtendableThing for ThingExtension {
567    /// #     type ArraySchema = ArraySchemaExtension;
568    /// #     /* Other types set to `()` */
569    /// #     type Form = ();
570    /// #     type InteractionAffordance = ();
571    /// #     type PropertyAffordance = ();
572    /// #     type ActionAffordance = ();
573    /// #     type EventAffordance = ();
574    /// #     type ExpectedResponse = ();
575    /// #     type DataSchema = ();
576    /// #     type ObjectSchema = ();
577    /// # }
578    /// #
579    /// let thing = Thing::builder("Thing name")
580    ///     .ext(ThingExtension {})
581    ///     .finish_extend()
582    ///     .schema_definition("test", |b| b.ext(()).finish_extend().tuple())
583    ///     .build()
584    ///     .unwrap();
585    /// ```
586    ///
587    /// In this case, the following is necessary:
588    ///
589    /// ```
590    /// # use serde::{Deserialize, Serialize};
591    /// # use serde_json::json;
592    /// # use wot_td::{
593    /// #     builder::data_schema::SpecializableDataSchema,
594    /// #     extend::{Extend, ExtendableThing},
595    /// #     thing::Thing,
596    /// # };
597    /// #
598    /// # #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
599    /// # struct ThingExtension {}
600    /// #
601    /// # #[derive(Debug, PartialEq, Serialize, Deserialize)]
602    /// # struct NotDefaultableU32(u32);
603    /// #
604    /// # #[derive(Debug, PartialEq, Serialize, Deserialize)]
605    /// # struct ArraySchemaExtension {
606    /// #     array_field: NotDefaultableU32,
607    /// # }
608    /// #
609    /// # impl ExtendableThing for ThingExtension {
610    /// #     type ArraySchema = ArraySchemaExtension;
611    /// #     /* Other types set to `()` */
612    /// #     type Form = ();
613    /// #     type InteractionAffordance = ();
614    /// #     type PropertyAffordance = ();
615    /// #     type ActionAffordance = ();
616    /// #     type EventAffordance = ();
617    /// #     type ExpectedResponse = ();
618    /// #     type DataSchema = ();
619    /// #     type ObjectSchema = ();
620    /// # }
621    /// #
622    /// let thing = Thing::builder("Thing name")
623    ///     .ext(ThingExtension {})
624    ///     .finish_extend()
625    ///     .schema_definition("test", |b| {
626    ///         b.ext(()).finish_extend().tuple_ext(|b| {
627    ///             b.ext(ArraySchemaExtension {
628    ///                 array_field: NotDefaultableU32(42),
629    ///             })
630    ///         })
631    ///     })
632    ///     .build()
633    ///     .unwrap();
634    /// #
635    /// # assert_eq!(
636    /// #     serde_json::to_value(thing).unwrap(),
637    /// #     json!({
638    /// #         "@context": "https://www.w3.org/2022/wot/td/v1.1",
639    /// #         "title": "Thing name",
640    /// #         "schemaDefinitions": {
641    /// #             "test": {
642    /// #                 "type": "array",
643    /// #                 "items": [],
644    /// #                 "array_field": 42,
645    /// #                 "readOnly": false,
646    /// #                 "writeOnly": false,
647    /// #             }
648    /// #         },
649    /// #         "security": [],
650    /// #         "securityDefinitions": {},
651    /// #     })
652    /// # );
653    /// ```
654    fn tuple(self) -> Self::Tuple
655    where
656        AS: Default;
657
658    /// Specialize the builder into an _array_ data schema builder to represent a _homogeneous
659    /// list_, initializing the array extensions with default values.
660    ///
661    /// Note that this function can only be called if `AS` implements [`Default`], use
662    /// [`vec_ext`] otherwise.
663    ///
664    /// [`vec_ext`]: Self::vec_ext
665    ///
666    /// # Examples
667    /// ```
668    /// # use serde::{Deserialize, Serialize};
669    /// # use serde_json::json;
670    /// # use wot_td::{
671    /// #     builder::data_schema::SpecializableDataSchema, extend::ExtendableThing, thing::Thing,
672    /// # };
673    /// #
674    /// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
675    /// struct ThingExtension {}
676    ///
677    /// #[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
678    /// struct ArraySchemaExtension {
679    ///     array_field: u32,
680    /// }
681    ///
682    /// impl ExtendableThing for ThingExtension {
683    ///     type ArraySchema = ArraySchemaExtension;
684    ///     /* Other types set to `()` */
685    /// #   type Form = ();
686    /// #   type InteractionAffordance = ();
687    /// #   type PropertyAffordance = ();
688    /// #   type ActionAffordance = ();
689    /// #   type EventAffordance = ();
690    /// #   type ExpectedResponse = ();
691    /// #   type DataSchema = ();
692    /// #   type ObjectSchema = ();
693    /// }
694    ///
695    /// let thing = Thing::builder("Thing name")
696    ///     .ext(ThingExtension {})
697    ///     .finish_extend()
698    ///     .schema_definition("test", |b| b.ext(()).finish_extend().vec())
699    ///     .build()
700    ///     .unwrap();
701    ///
702    /// assert_eq!(
703    ///     serde_json::to_value(thing).unwrap(),
704    ///     json!({
705    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
706    ///         "title": "Thing name",
707    ///         "schemaDefinitions": {
708    ///             "test": {
709    ///                 "type": "array",
710    ///                 "array_field": 0,
711    ///                 "readOnly": false,
712    ///                 "writeOnly": false,
713    ///             }
714    ///         },
715    ///         "security": [],
716    ///         "securityDefinitions": {},
717    ///     })
718    /// );
719    /// ```
720    ///
721    /// The following does not work instead:
722    ///
723    /// ```compile_fail
724    /// # use serde::{Deserialize, Serialize};
725    /// # use serde_json::json;
726    /// # use wot_td::{
727    /// #     builder::data_schema::SpecializableDataSchema, extend::ExtendableThing, thing::Thing,
728    /// # };
729    /// #
730    /// # #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
731    /// # struct ThingExtension {}
732    /// #
733    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
734    /// struct NotDefaultableU32(u32);
735    ///
736    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
737    /// struct ArraySchemaExtension {
738    ///     array_field: NotDefaultableU32,
739    /// }
740    ///
741    /// # impl ExtendableThing for ThingExtension {
742    /// #     type ArraySchema = ArraySchemaExtension;
743    /// #     /* Other types set to `()` */
744    /// #     type Form = ();
745    /// #     type InteractionAffordance = ();
746    /// #     type PropertyAffordance = ();
747    /// #     type ActionAffordance = ();
748    /// #     type EventAffordance = ();
749    /// #     type ExpectedResponse = ();
750    /// #     type DataSchema = ();
751    /// #     type ObjectSchema = ();
752    /// # }
753    /// #
754    /// let thing = Thing::builder("Thing name")
755    ///     .ext(ThingExtension {})
756    ///     .finish_extend()
757    ///     .schema_definition("test", |b| b.ext(()).finish_extend().vec())
758    ///     .build()
759    ///     .unwrap();
760    /// ```
761    ///
762    /// In this case, the following is necessary:
763    ///
764    /// ```
765    /// # use serde::{Deserialize, Serialize};
766    /// # use serde_json::json;
767    /// # use wot_td::{
768    /// #     builder::data_schema::SpecializableDataSchema,
769    /// #     extend::{Extend, ExtendableThing},
770    /// #     thing::Thing,
771    /// # };
772    /// #
773    /// # #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
774    /// # struct ThingExtension {}
775    /// #
776    /// # #[derive(Debug, PartialEq, Serialize, Deserialize)]
777    /// # struct NotDefaultableU32(u32);
778    /// #
779    /// # #[derive(Debug, PartialEq, Serialize, Deserialize)]
780    /// # struct ArraySchemaExtension {
781    /// #     array_field: NotDefaultableU32,
782    /// # }
783    /// #
784    /// # impl ExtendableThing for ThingExtension {
785    /// #     type ArraySchema = ArraySchemaExtension;
786    /// #     /* Other types set to `()` */
787    /// #     type Form = ();
788    /// #     type InteractionAffordance = ();
789    /// #     type PropertyAffordance = ();
790    /// #     type ActionAffordance = ();
791    /// #     type EventAffordance = ();
792    /// #     type ExpectedResponse = ();
793    /// #     type DataSchema = ();
794    /// #     type ObjectSchema = ();
795    /// # }
796    /// #
797    /// let thing = Thing::builder("Thing name")
798    ///     .ext(ThingExtension {})
799    ///     .finish_extend()
800    ///     .schema_definition("test", |b| {
801    ///         b.ext(()).finish_extend().vec_ext(|b| {
802    ///             b.ext(ArraySchemaExtension {
803    ///                 array_field: NotDefaultableU32(42),
804    ///             })
805    ///         })
806    ///     })
807    ///     .build()
808    ///     .unwrap();
809    /// #
810    /// # assert_eq!(
811    /// #     serde_json::to_value(thing).unwrap(),
812    /// #     json!({
813    /// #         "@context": "https://www.w3.org/2022/wot/td/v1.1",
814    /// #         "title": "Thing name",
815    /// #         "schemaDefinitions": {
816    /// #             "test": {
817    /// #                 "type": "array",
818    /// #                 "array_field": 42,
819    /// #                 "readOnly": false,
820    /// #                 "writeOnly": false,
821    /// #             }
822    /// #         },
823    /// #         "security": [],
824    /// #         "securityDefinitions": {},
825    /// #     })
826    /// # );
827    /// ```
828    fn vec(self) -> Self::Vec
829    where
830        AS: Default;
831
832    /// Specialize the builder into an _array_ data schema builder representing a tuple, passing a
833    /// function to create the array extensions.
834    ///
835    /// # Example
836    ///
837    /// ```
838    /// # use serde::{Deserialize, Serialize};
839    /// # use serde_json::json;
840    /// # use wot_td::{
841    /// #     builder::data_schema::SpecializableDataSchema,
842    /// #     extend::{Extend, ExtendableThing},
843    /// #     thing::Thing,
844    /// # };
845    /// #
846    /// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
847    /// struct ThingExtension {}
848    ///
849    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
850    /// struct NotDefaultableU32(u32);
851    ///
852    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
853    /// struct ArraySchemaExtension {
854    ///     array_field: NotDefaultableU32,
855    /// }
856    ///
857    /// impl ExtendableThing for ThingExtension {
858    ///     type ArraySchema = ArraySchemaExtension;
859    /// #   /* Other types set to `()` */
860    /// #   type Form = ();
861    /// #   type InteractionAffordance = ();
862    /// #   type PropertyAffordance = ();
863    /// #   type ActionAffordance = ();
864    /// #   type EventAffordance = ();
865    /// #   type ExpectedResponse = ();
866    /// #   type DataSchema = ();
867    /// #   type ObjectSchema = ();
868    /// }
869    ///
870    /// let thing = Thing::builder("Thing name")
871    ///     .ext(ThingExtension {})
872    ///     .finish_extend()
873    ///     .schema_definition("test", |b| {
874    ///         b.ext(()).finish_extend().tuple_ext(|b| {
875    ///             b.ext(ArraySchemaExtension {
876    ///                 array_field: NotDefaultableU32(42),
877    ///             })
878    ///         })
879    ///     })
880    ///     .build()
881    ///     .unwrap();
882    ///
883    /// assert_eq!(
884    ///     serde_json::to_value(thing).unwrap(),
885    ///     json!({
886    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
887    ///         "title": "Thing name",
888    ///         "schemaDefinitions": {
889    ///             "test": {
890    ///                 "type": "array",
891    ///                 "items": [],
892    ///                 "array_field": 42,
893    ///                 "readOnly": false,
894    ///                 "writeOnly": false,
895    ///             }
896    ///         },
897    ///         "security": [],
898    ///         "securityDefinitions": {},
899    ///     })
900    /// );
901    /// ```
902    fn tuple_ext<F>(self, f: F) -> Self::Tuple
903    where
904        F: FnOnce(AS::Empty) -> AS,
905        AS: Extendable;
906
907    /// Specialize the builder into an _array_ data schema builder representing a _homogeneous
908    /// list_, passing a function to create the array extensions.
909    ///
910    /// # Example
911    ///
912    /// ```
913    /// # use serde::{Deserialize, Serialize};
914    /// # use serde_json::json;
915    /// # use wot_td::{
916    /// #     builder::data_schema::SpecializableDataSchema,
917    /// #     extend::{Extend, ExtendableThing},
918    /// #     thing::Thing,
919    /// # };
920    /// #
921    /// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
922    /// struct ThingExtension {}
923    ///
924    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
925    /// struct NotDefaultableU32(u32);
926    ///
927    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
928    /// struct ArraySchemaExtension {
929    ///     array_field: NotDefaultableU32,
930    /// }
931    ///
932    /// impl ExtendableThing for ThingExtension {
933    ///     type ArraySchema = ArraySchemaExtension;
934    /// #   /* Other types set to `()` */
935    /// #   type Form = ();
936    /// #   type InteractionAffordance = ();
937    /// #   type PropertyAffordance = ();
938    /// #   type ActionAffordance = ();
939    /// #   type EventAffordance = ();
940    /// #   type ExpectedResponse = ();
941    /// #   type DataSchema = ();
942    /// #   type ObjectSchema = ();
943    /// }
944    ///
945    /// let thing = Thing::builder("Thing name")
946    ///     .ext(ThingExtension {})
947    ///     .finish_extend()
948    ///     .schema_definition("test", |b| {
949    ///         b.ext(()).finish_extend().vec_ext(|b| {
950    ///             b.ext(ArraySchemaExtension {
951    ///                 array_field: NotDefaultableU32(42),
952    ///             })
953    ///         })
954    ///     })
955    ///     .build()
956    ///     .unwrap();
957    ///
958    /// assert_eq!(
959    ///     serde_json::to_value(thing).unwrap(),
960    ///     json!({
961    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
962    ///         "title": "Thing name",
963    ///         "schemaDefinitions": {
964    ///             "test": {
965    ///                 "type": "array",
966    ///                 "array_field": 42,
967    ///                 "readOnly": false,
968    ///                 "writeOnly": false,
969    ///             }
970    ///         },
971    ///         "security": [],
972    ///         "securityDefinitions": {},
973    ///     })
974    /// );
975    /// ```
976    fn vec_ext<F>(self, f: F) -> Self::Vec
977    where
978        F: FnOnce(AS::Empty) -> AS,
979        AS: Extendable;
980
981    /// Specialize the builder into a _boolean_ data schema builder.
982    fn bool(self) -> Self::Stateless;
983
984    /// Specialize the builder into a _number_ data schema builder.
985    fn number(self) -> Self::Number;
986
987    /// Specialize the builder into an _integer_ data schema builder.
988    fn integer(self) -> Self::Integer;
989
990    /// Specialize the builder into an _object_ data schema builder, initializing the object
991    /// extensions with default values.
992    ///
993    /// Note that this function can only be called if `OS` implements [`Default`], use
994    /// [`object_ext`] otherwise.
995    ///
996    /// [`object_ext`]: Self::object_ext
997    ///
998    /// # Examples
999    /// ```
1000    /// # use serde::{Deserialize, Serialize};
1001    /// # use serde_json::json;
1002    /// # use wot_td::{
1003    /// #     builder::data_schema::SpecializableDataSchema, extend::ExtendableThing, thing::Thing,
1004    /// # };
1005    /// #
1006    /// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
1007    /// struct ThingExtension {}
1008    ///
1009    /// #[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
1010    /// struct ObjectSchemaExtension {
1011    ///     object_field: u32,
1012    /// }
1013    ///
1014    /// impl ExtendableThing for ThingExtension {
1015    ///     type ObjectSchema = ObjectSchemaExtension;
1016    ///     /* Other types set to `()` */
1017    /// #   type Form = ();
1018    /// #   type InteractionAffordance = ();
1019    /// #   type PropertyAffordance = ();
1020    /// #   type ActionAffordance = ();
1021    /// #   type EventAffordance = ();
1022    /// #   type ExpectedResponse = ();
1023    /// #   type DataSchema = ();
1024    /// #   type ArraySchema = ();
1025    /// }
1026    ///
1027    /// let thing = Thing::builder("Thing name")
1028    ///     .ext(ThingExtension {})
1029    ///     .finish_extend()
1030    ///     .schema_definition("test", |b| b.ext(()).finish_extend().object())
1031    ///     .build()
1032    ///     .unwrap();
1033    ///
1034    /// assert_eq!(
1035    ///     serde_json::to_value(thing).unwrap(),
1036    ///     json!({
1037    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1038    ///         "title": "Thing name",
1039    ///         "schemaDefinitions": {
1040    ///             "test": {
1041    ///                 "type": "object",
1042    ///                 "object_field": 0,
1043    ///                 "readOnly": false,
1044    ///                 "writeOnly": false,
1045    ///             }
1046    ///         },
1047    ///         "security": [],
1048    ///         "securityDefinitions": {},
1049    ///     })
1050    /// );
1051    /// ```
1052    ///
1053    /// The following does not work instead:
1054    ///
1055    /// ```compile_fail
1056    /// # use serde::{Deserialize, Serialize};
1057    /// # use serde_json::json;
1058    /// # use wot_td::{
1059    /// #     builder::data_schema::SpecializableDataSchema, extend::ExtendableThing, thing::Thing,
1060    /// # };
1061    /// #
1062    /// # #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
1063    /// # struct ThingExtension {}
1064    /// #
1065    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
1066    /// struct NotDefaultableU32(u32);
1067    ///
1068    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
1069    /// struct ObjectSchemaExtension {
1070    ///     object_field: NotDefaultableU32,
1071    /// }
1072    ///
1073    /// # impl ExtendableThing for ThingExtension {
1074    /// #     type ArraySchema = ArraySchemaExtension;
1075    /// #     /* Other types set to `()` */
1076    /// #     type Form = ();
1077    /// #     type InteractionAffordance = ();
1078    /// #     type PropertyAffordance = ();
1079    /// #     type ActionAffordance = ();
1080    /// #     type EventAffordance = ();
1081    /// #     type ExpectedResponse = ();
1082    /// #     type DataSchema = ();
1083    /// #     type ObjectSchema = ();
1084    /// # }
1085    /// #
1086    /// let thing = Thing::builder("Thing name")
1087    ///     .ext(ThingExtension {})
1088    ///     .finish_extend()
1089    ///     .schema_definition("test", |b| b.ext(()).finish_extend().object())
1090    ///     .build()
1091    ///     .unwrap();
1092    /// ```
1093    ///
1094    /// In this case, the following is necessary:
1095    ///
1096    /// ```
1097    /// # use serde::{Deserialize, Serialize};
1098    /// # use serde_json::json;
1099    /// # use wot_td::{
1100    /// #     builder::data_schema::SpecializableDataSchema,
1101    /// #     extend::{Extend, ExtendableThing},
1102    /// #     thing::Thing,
1103    /// # };
1104    /// #
1105    /// # #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
1106    /// # struct ThingExtension {}
1107    /// #
1108    /// # #[derive(Debug, PartialEq, Serialize, Deserialize)]
1109    /// # struct NotDefaultableU32(u32);
1110    /// #
1111    /// # #[derive(Debug, PartialEq, Serialize, Deserialize)]
1112    /// # struct ObjectSchemaExtension {
1113    /// #     object_field: NotDefaultableU32,
1114    /// # }
1115    /// #
1116    /// # impl ExtendableThing for ThingExtension {
1117    /// #     type ObjectSchema = ObjectSchemaExtension;
1118    /// #     /* Other types set to `()` */
1119    /// #     type Form = ();
1120    /// #     type InteractionAffordance = ();
1121    /// #     type PropertyAffordance = ();
1122    /// #     type ActionAffordance = ();
1123    /// #     type EventAffordance = ();
1124    /// #     type ExpectedResponse = ();
1125    /// #     type DataSchema = ();
1126    /// #     type ArraySchema = ();
1127    /// # }
1128    /// #
1129    /// let thing = Thing::builder("Thing name")
1130    ///     .ext(ThingExtension {})
1131    ///     .finish_extend()
1132    ///     .schema_definition("test", |b| {
1133    ///         b.ext(()).finish_extend().object_ext(|b| {
1134    ///             b.ext(ObjectSchemaExtension {
1135    ///                 object_field: NotDefaultableU32(42),
1136    ///             })
1137    ///         })
1138    ///     })
1139    ///     .build()
1140    ///     .unwrap();
1141    /// #
1142    /// # assert_eq!(
1143    /// #     serde_json::to_value(thing).unwrap(),
1144    /// #     json!({
1145    /// #         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1146    /// #         "title": "Thing name",
1147    /// #         "schemaDefinitions": {
1148    /// #             "test": {
1149    /// #                 "type": "object",
1150    /// #                 "object_field": 42,
1151    /// #                 "readOnly": false,
1152    /// #                 "writeOnly": false,
1153    /// #             }
1154    /// #         },
1155    /// #         "security": [],
1156    /// #         "securityDefinitions": {},
1157    /// #     })
1158    /// # );
1159    /// ```
1160    fn object(self) -> Self::Object
1161    where
1162        OS: Default;
1163
1164    /// Specialize the builder into an _object_ data schema builder, passing a function to create
1165    /// the object extensions.
1166    ///
1167    /// # Example
1168    ///
1169    /// ```
1170    /// # use serde::{Deserialize, Serialize};
1171    /// # use serde_json::json;
1172    /// # use wot_td::{
1173    /// #     builder::data_schema::SpecializableDataSchema,
1174    /// #     extend::{Extend, ExtendableThing},
1175    /// #     thing::Thing,
1176    /// # };
1177    /// #
1178    /// #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
1179    /// struct ThingExtension {}
1180    ///
1181    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
1182    /// struct NotDefaultableU32(u32);
1183    ///
1184    /// #[derive(Debug, PartialEq, Serialize, Deserialize)]
1185    /// struct ObjectSchemaExtension {
1186    ///     object_field: NotDefaultableU32,
1187    /// }
1188    ///
1189    /// impl ExtendableThing for ThingExtension {
1190    ///     type ObjectSchema = ObjectSchemaExtension;
1191    /// #   /* Other types set to `()` */
1192    /// #   type Form = ();
1193    /// #   type InteractionAffordance = ();
1194    /// #   type PropertyAffordance = ();
1195    /// #   type ActionAffordance = ();
1196    /// #   type EventAffordance = ();
1197    /// #   type ExpectedResponse = ();
1198    /// #   type DataSchema = ();
1199    /// #   type ArraySchema = ();
1200    /// }
1201    ///
1202    /// let thing = Thing::builder("Thing name")
1203    ///     .ext(ThingExtension {})
1204    ///     .finish_extend()
1205    ///     .schema_definition("test", |b| {
1206    ///         b.ext(()).finish_extend().object_ext(|b| {
1207    ///             b.ext(ObjectSchemaExtension {
1208    ///                 object_field: NotDefaultableU32(42),
1209    ///             })
1210    ///         })
1211    ///     })
1212    ///     .build()
1213    ///     .unwrap();
1214    ///
1215    /// assert_eq!(
1216    ///     serde_json::to_value(thing).unwrap(),
1217    ///     json!({
1218    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1219    ///         "title": "Thing name",
1220    ///         "schemaDefinitions": {
1221    ///             "test": {
1222    ///                 "type": "object",
1223    ///                 "object_field": 42,
1224    ///                 "readOnly": false,
1225    ///                 "writeOnly": false,
1226    ///             }
1227    ///         },
1228    ///         "security": [],
1229    ///         "securityDefinitions": {},
1230    ///     })
1231    /// );
1232    /// ```
1233    fn object_ext<F>(self, f: F) -> Self::Object
1234    where
1235        F: FnOnce(OS::Empty) -> OS,
1236        OS: Extendable;
1237
1238    /// Specialize the builder into a _string_ data schema builder.
1239    fn string(self) -> Self::String;
1240
1241    /// Specialize the builder into a _null_ data schema builder.
1242    fn null(self) -> Self::Stateless;
1243
1244    /// Specialize the builder into a _constant_ data schema builder.
1245    fn constant(self, value: impl Into<Value>) -> Self::Constant;
1246}
1247
1248/// An interface to specialize an _enumerable_ version of a
1249/// [`DataSchema`](crate::thing::DataSchema).
1250///
1251/// An _unspecialized_ data schema can be _specialized_ into an _enumerable_ data schema, which
1252/// then supports adding more variants to the enumeration. This trait allows this behavior, keeping
1253/// it separated from [`SpecializableDataSchema`] that is not implemented for _specialized_ data
1254/// schemas.
1255///
1256/// # Notes
1257///
1258/// - This trait *should not* be implemented directly, even if it is not sealed.
1259pub trait EnumerableDataSchema<DS, AS, OS, Extended>:
1260    BuildableDataSchema<DS, AS, OS, Extended>
1261{
1262    /// The _enumeration_ specialization of the data schema builder.
1263    type Target: BuildableDataSchema<DS, AS, OS, Extended>;
1264
1265    /// Returns a _specialized_ enumeration data schema and adds a variant to the `enumeration`
1266    /// field. It can be implemented for specialized _enumeration_ data schemas.
1267    ///
1268    /// # Example
1269    ///
1270    /// ```
1271    /// # use serde_json::json;
1272    /// # use wot_td::{builder::data_schema::EnumerableDataSchema, thing::Thing};
1273    /// #
1274    /// let thing = Thing::builder("Thing name")
1275    ///     .finish_extend()
1276    ///     .schema_definition("test", |b| {
1277    ///         b.finish_extend()
1278    ///             .enumeration("variant1")
1279    ///             .enumeration("variant2")
1280    ///             .enumeration("variant3")
1281    ///     })
1282    ///     .build()
1283    ///     .unwrap();
1284    ///
1285    /// assert_eq!(
1286    ///     serde_json::to_value(thing).unwrap(),
1287    ///     json!({
1288    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1289    ///         "title": "Thing name",
1290    ///         "schemaDefinitions": {
1291    ///             "test": {
1292    ///                 "enum": ["variant1", "variant2", "variant3"],
1293    ///                 "readOnly": false,
1294    ///                 "writeOnly": false,
1295    ///             }
1296    ///         },
1297    ///         "security": [],
1298    ///         "securityDefinitions": {},
1299    ///     })
1300    /// );
1301    /// ```
1302    fn enumeration(self, value: impl Into<Value>) -> Self::Target;
1303}
1304
1305/// An interface to specialize a _union_ version of a [`DataSchema`](crate::thing::DataSchema).
1306///
1307/// An _unspecialized_ data schema can be _specialized_ into an _union_ data schema, which then
1308/// supports adding more data schemas to the `one_of` fields. This trait allows this behavior,
1309/// keeping it separated from [`SpecializableDataSchema`] that is not implemented for _specialized_
1310/// data schemas.
1311///
1312/// # Notes
1313///
1314/// - This trait *should not* be implemented directly, even if it is not sealed.
1315pub trait UnionDataSchema<DS, AS, OS>: BuildableDataSchema<DS, AS, OS, Extended> {
1316    /// The _union_ specialization of the data schema builder.
1317    type Target: BuildableDataSchema<DS, AS, OS, Extended>;
1318
1319    /// Returns a _specialized_ union data schema and adds a data schema to the `one_of` field. It
1320    /// can be implemented for specialized _one_of_ data schemas.
1321    ///
1322    /// # Example
1323    ///
1324    /// ```
1325    /// # use serde_json::json;
1326    /// # use wot_td::{
1327    /// #     builder::data_schema::{SpecializableDataSchema, UnionDataSchema},
1328    /// #     thing::Thing,
1329    /// # };
1330    /// #
1331    /// let thing = Thing::builder("Thing name")
1332    ///     .finish_extend()
1333    ///     .schema_definition("test", |b| {
1334    ///         b.finish_extend()
1335    ///             .one_of(|b| b.finish_extend().number())
1336    ///             .one_of(|b| b.finish_extend().integer())
1337    ///             .one_of(|b| b.finish_extend().string())
1338    ///     })
1339    ///     .build()
1340    ///     .unwrap();
1341    ///
1342    /// assert_eq!(
1343    ///     serde_json::to_value(thing).unwrap(),
1344    ///     json!({
1345    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1346    ///         "title": "Thing name",
1347    ///         "schemaDefinitions": {
1348    ///             "test": {
1349    ///                 "oneOf": [
1350    ///                     {
1351    ///                         "type": "number",
1352    ///                         "readOnly": false,
1353    ///                         "writeOnly": false,
1354    ///                     },
1355    ///                     {
1356    ///                         "type": "integer",
1357    ///                         "readOnly": false,
1358    ///                         "writeOnly": false,
1359    ///                     },
1360    ///                     {
1361    ///                         "type": "string",
1362    ///                         "readOnly": false,
1363    ///                         "writeOnly": false,
1364    ///                     },
1365    ///                 ],
1366    ///                 "readOnly": false,
1367    ///                 "writeOnly": false,
1368    ///             }
1369    ///         },
1370    ///         "security": [],
1371    ///         "securityDefinitions": {},
1372    ///     })
1373    /// );
1374    /// ```
1375    fn one_of<F, T>(self, f: F) -> Self::Target
1376    where
1377        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
1378        DS: Extendable,
1379        T: Into<UncheckedDataSchema<DS, AS, OS>>;
1380}
1381
1382/// An interface to specialize a _read-only_/_write-only_ version of a
1383/// [`DataSchema`](crate::thing::DataSchema).
1384///
1385/// Some specializations of `DataSchema` can be set as _read-only_ or _write-only_. When
1386/// implemented, this allows a safe abstraction over these situations, avoiding conflicting states
1387/// a compile-time.
1388///
1389/// # Notes
1390///
1391/// - This trait *should not* be implemented directly, even if it is not sealed.
1392pub trait ReadableWriteableDataSchema<DS, AS, OS, Extended>:
1393    BuildableDataSchema<DS, AS, OS, Extended>
1394{
1395    /// The _read-only_ variant of the data schema builder.
1396    type ReadOnly: BuildableDataSchema<DS, AS, OS, Extended>;
1397
1398    /// The _write-only_ variant of the data schema builder.
1399    type WriteOnly: BuildableDataSchema<DS, AS, OS, Extended>;
1400
1401    /// Creates a _read-only_ variant of the data schema builder.
1402    ///
1403    /// # Examples
1404    ///
1405    /// ```
1406    /// # use serde_json::json;
1407    /// # use wot_td::{
1408    /// #     builder::data_schema::{
1409    /// #         IntegerDataSchemaBuilderLike, ReadableWriteableDataSchema, SpecializableDataSchema,
1410    /// #     },
1411    /// #     thing::Thing,
1412    /// # };
1413    /// #
1414    /// let thing = Thing::builder("Thing name")
1415    ///     .finish_extend()
1416    ///     .schema_definition("test", |b| {
1417    ///         b.finish_extend()
1418    ///             .integer()
1419    ///             .minimum(5)
1420    ///             .read_only()
1421    ///             .maximum(10)
1422    ///     })
1423    ///     .build()
1424    ///     .unwrap();
1425    ///
1426    /// assert_eq!(
1427    ///     serde_json::to_value(thing).unwrap(),
1428    ///     json!({
1429    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1430    ///         "title": "Thing name",
1431    ///         "schemaDefinitions": {
1432    ///             "test": {
1433    ///                 "type": "integer",
1434    ///                 "readOnly": true,
1435    ///                 "writeOnly": false,
1436    ///                 "minimum": 5,
1437    ///                 "maximum": 10,
1438    ///             }
1439    ///         },
1440    ///         "security": [],
1441    ///         "securityDefinitions": {},
1442    ///     })
1443    /// );
1444    /// ```
1445    ///
1446    /// The example using `write_only` is analogous. However, it is not possible to call both
1447    /// `read_only` and `write_only` on the same data schema building chain:
1448    ///
1449    /// ```compile_fail
1450    /// # use serde_json::json;
1451    /// # use wot_td::{
1452    /// #     builder::data_schema::{ReadableWriteableDataSchema, SpecializableDataSchema},
1453    /// #     thing::Thing,
1454    /// # };
1455    /// #
1456    /// let thing = Thing::builder("Thing name")
1457    ///     .finish_extend()
1458    ///     .schema_definition("test", |b| {
1459    ///         b.finish_extend().integer().read_only().write_only()
1460    ///     })
1461    ///     .build()
1462    ///     .unwrap();
1463    /// ```
1464    ///
1465    fn read_only(self) -> Self::ReadOnly;
1466
1467    /// Creates a _write-only_ variant of the data schema builder.
1468    ///
1469    /// See [`read_only`] for examples.
1470    ///
1471    /// [`read_only`]: Self::read_only
1472    fn write_only(self) -> Self::WriteOnly;
1473}
1474
1475/// The builder for an [`ArraySchema`](crate::thing::ArraySchema) builder with a set of `items` to
1476/// represent a tuple of elements.
1477pub struct TupleDataSchemaBuilder<Inner, DS, AS, OS> {
1478    inner: Inner,
1479    items: Vec<UncheckedDataSchema<DS, AS, OS>>,
1480
1481    /// Array data schema extension.
1482    pub other: AS,
1483}
1484
1485/// The builder for an [`ArraySchema`](crate::thing::ArraySchema) builder with a single `item` to
1486/// represent the underlying type of a _homogeneous list_.
1487pub struct VecDataSchemaBuilder<Inner, DS, AS, OS> {
1488    inner: Inner,
1489    item: Option<UncheckedDataSchema<DS, AS, OS>>,
1490    min_items: Option<u32>,
1491    max_items: Option<u32>,
1492
1493    /// Array data schema extension.
1494    pub other: AS,
1495}
1496
1497/// The builder for an [`NumberSchema`](crate::thing::NumberSchema) builder.
1498pub struct NumberDataSchemaBuilder<Inner> {
1499    inner: Inner,
1500    maximum: Option<Maximum<f64>>,
1501    minimum: Option<Minimum<f64>>,
1502    multiple_of: Option<f64>,
1503}
1504
1505/// The builder for an [`IntegerSchema`](crate::thing::IntegerSchema) builder.
1506pub struct IntegerDataSchemaBuilder<Inner> {
1507    inner: Inner,
1508    maximum: Option<Maximum<i64>>,
1509    minimum: Option<Minimum<i64>>,
1510    multiple_of: Option<NonZeroU64>,
1511}
1512
1513/// The builder for an [`ObjectSchema`](crate::thing::ObjectSchema) builder.
1514pub struct ObjectDataSchemaBuilder<Inner, DS, AS, OS> {
1515    inner: Inner,
1516    properties: Vec<(String, UncheckedDataSchema<DS, AS, OS>)>,
1517    required: Vec<String>,
1518
1519    /// Object data schema extension.
1520    pub other: OS,
1521}
1522
1523/// The builder for an [`StringSchema`](crate::thing::StringSchema) builder.
1524pub struct StringDataSchemaBuilder<Inner> {
1525    inner: Inner,
1526    min_length: Option<u32>,
1527    max_length: Option<u32>,
1528    pattern: Option<String>,
1529    content_encoding: Option<String>,
1530    content_media_type: Option<String>,
1531}
1532
1533/// A _typetag_ for a `DataSchema` builder that has the
1534/// [`enumeration`](crate::thing::DataSchema::enumeration) field populated.
1535pub struct EnumDataSchemaBuilder<Inner> {
1536    inner: Inner,
1537}
1538
1539/// A _typetag_ for a `DataSchema` builder that has the
1540/// [`one_of`](crate::thing::DataSchema::one_of) field populated.
1541pub struct OneOfDataSchemaBuilder<Inner> {
1542    inner: Inner,
1543}
1544
1545/// The type of a stateless `DataSchema` specialization.
1546pub enum StatelessDataSchemaType {
1547    /// A _boolean_ specialization.
1548    Boolean,
1549
1550    /// A _null_ specialization.
1551    Null,
1552}
1553
1554/// A _typetag_ for a stateless specialized `DataSchema` builder.
1555pub struct StatelessDataSchemaBuilder<Inner> {
1556    inner: Inner,
1557    ty: Option<StatelessDataSchemaType>,
1558}
1559
1560/// A _typetag_ for a read-only `DataSchema` builder.
1561pub struct ReadOnly<Inner> {
1562    inner: Inner,
1563}
1564
1565/// A _typetag_ for a write-only `DataSchema` builder.
1566pub struct WriteOnly<Inner> {
1567    inner: Inner,
1568}
1569
1570macro_rules! opt_field_decl {
1571    ($($field:ident : $ty:ty),* $(,)?) => {
1572        $(
1573            #[doc = concat!("Sets the value of the `", stringify!($field), "` field.")]
1574            fn $field(self, value: $ty) -> Self;
1575        )*
1576    };
1577}
1578
1579macro_rules! opt_field_into_decl {
1580    ($($field:ident : $ty:ty),* $(,)?) => {
1581        $(
1582            #[doc = concat!("Sets the value of the `", stringify!($field), "` field.")]
1583            fn $field(self, value: impl Into<$ty>) -> Self;
1584        )*
1585    };
1586}
1587
1588/// An interface for things behaving like an array data schema builder representing a _homogeneous
1589/// list_.
1590pub trait VecDataSchemaBuilderLike<DS, AS, OS> {
1591    opt_field_decl!(min_items: u32, max_items: u32);
1592
1593    /// Sets the data schema of the underlying type.
1594    ///
1595    /// # Example
1596    ///
1597    /// ```
1598    /// # use serde_json::json;
1599    /// # use wot_td::{
1600    /// #     builder::data_schema::{VecDataSchemaBuilderLike, SpecializableDataSchema},
1601    /// #     thing::Thing,
1602    /// # };
1603    /// #
1604    /// let thing = Thing::builder("Thing name")
1605    ///     .finish_extend()
1606    ///     .schema_definition("test", |b| {
1607    ///         b.finish_extend()
1608    ///             .vec()
1609    ///             .set_item(|b| b.finish_extend().number())
1610    ///     })
1611    ///     .build()
1612    ///     .unwrap();
1613    ///
1614    /// assert_eq!(
1615    ///     serde_json::to_value(thing).unwrap(),
1616    ///     json!({
1617    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1618    ///         "title": "Thing name",
1619    ///         "schemaDefinitions": {
1620    ///             "test": {
1621    ///                 "type": "array",
1622    ///                 "items": {
1623    ///                     "type": "number",
1624    ///                     "readOnly": false,
1625    ///                     "writeOnly": false,
1626    ///                 },
1627    ///                 "readOnly": false,
1628    ///                 "writeOnly": false,
1629    ///             }
1630    ///         },
1631    ///         "security": [],
1632    ///         "securityDefinitions": {},
1633    ///     })
1634    /// );
1635    /// ```
1636    fn set_item<F, T>(self, f: F) -> Self
1637    where
1638        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
1639        DS: Extendable,
1640        T: Into<UncheckedDataSchema<DS, AS, OS>>;
1641}
1642
1643/// An interface for things behaving like an array data schema builder representing a tuple.
1644pub trait TupleDataSchemaBuilderLike<DS, AS, OS> {
1645    /// Append an element to the tuple of inner data schemas.
1646    ///
1647    /// # Example
1648    ///
1649    /// ```
1650    /// # use serde_json::json;
1651    /// # use wot_td::{
1652    /// #     builder::data_schema::{TupleDataSchemaBuilderLike, SpecializableDataSchema},
1653    /// #     thing::Thing,
1654    /// # };
1655    /// #
1656    /// let thing = Thing::builder("Thing name")
1657    ///     .finish_extend()
1658    ///     .schema_definition("test", |b| {
1659    ///         b.finish_extend()
1660    ///             .tuple()
1661    ///             .append(|b| b.finish_extend().number())
1662    ///             .append(|b| b.finish_extend().null())
1663    ///     })
1664    ///     .build()
1665    ///     .unwrap();
1666    ///
1667    /// assert_eq!(
1668    ///     serde_json::to_value(thing).unwrap(),
1669    ///     json!({
1670    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1671    ///         "title": "Thing name",
1672    ///         "schemaDefinitions": {
1673    ///             "test": {
1674    ///                 "type": "array",
1675    ///                 "items": [
1676    ///                     {
1677    ///                         "type": "number",
1678    ///                         "readOnly": false,
1679    ///                         "writeOnly": false,
1680    ///                     },
1681    ///                     {
1682    ///                         "type": "null",
1683    ///                         "readOnly": false,
1684    ///                         "writeOnly": false,
1685    ///                     },
1686    ///                 ],
1687    ///                 "readOnly": false,
1688    ///                 "writeOnly": false,
1689    ///             }
1690    ///         },
1691    ///         "security": [],
1692    ///         "securityDefinitions": {},
1693    ///     })
1694    /// );
1695    /// ```
1696    fn append<F, T>(self, f: F) -> Self
1697    where
1698        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
1699        DS: Extendable,
1700        T: Into<UncheckedDataSchema<DS, AS, OS>>;
1701}
1702
1703/// An interface for things behaving like a number data schema builder.
1704pub trait NumberDataSchemaBuilderLike<DS, AS, OS> {
1705    opt_field_decl!(
1706        minimum: f64,
1707        maximum: f64,
1708        exclusive_minimum: f64,
1709        exclusive_maximum: f64,
1710        multiple_of: f64,
1711    );
1712}
1713
1714/// An interface for things behaving like an integer data schema builder.
1715pub trait IntegerDataSchemaBuilderLike<DS, AS, OS> {
1716    opt_field_decl!(
1717        minimum: i64,
1718        maximum: i64,
1719        exclusive_minimum: i64,
1720        exclusive_maximum: i64,
1721        multiple_of: NonZeroU64,
1722    );
1723}
1724
1725/// An interface for things behaving like an object data schema builder.
1726pub trait ObjectDataSchemaBuilderLike<DS, AS, OS> {
1727    /// Add a new property to the object.
1728    ///
1729    /// The `name` corresponds to the _key_ of the object.
1730    ///
1731    /// If `required` is true, the `name` is added to the
1732    /// [`required`](crate::thing::ObjectSchema::required) field.
1733    ///
1734    /// # Example
1735    ///
1736    /// ```
1737    /// # use serde_json::json;
1738    /// # use wot_td::{
1739    /// #     builder::data_schema::{ObjectDataSchemaBuilderLike, SpecializableDataSchema},
1740    /// #     thing::Thing,
1741    /// # };
1742    /// #
1743    /// let thing = Thing::builder("Thing name")
1744    ///     .finish_extend()
1745    ///     .schema_definition("test", |b| {
1746    ///         b.finish_extend()
1747    ///             .object()
1748    ///             .property("prop", true, |b| b.finish_extend().integer())
1749    ///             .property("other_prop", false, |b| b.finish_extend().number())
1750    ///     })
1751    ///     .build()
1752    ///     .unwrap();
1753    ///
1754    /// assert_eq!(
1755    ///     serde_json::to_value(thing).unwrap(),
1756    ///     json!({
1757    ///         "@context": "https://www.w3.org/2022/wot/td/v1.1",
1758    ///         "title": "Thing name",
1759    ///         "schemaDefinitions": {
1760    ///             "test": {
1761    ///                 "type": "object",
1762    ///                 "properties": {
1763    ///                     "prop": {
1764    ///                         "type": "integer",
1765    ///                         "readOnly": false,
1766    ///                         "writeOnly": false,
1767    ///                     },
1768    ///                     "other_prop": {
1769    ///                         "type": "number",
1770    ///                         "readOnly": false,
1771    ///                         "writeOnly": false,
1772    ///                     },
1773    ///                 },
1774    ///                 "required": ["prop"],
1775    ///                 "readOnly": false,
1776    ///                 "writeOnly": false,
1777    ///             }
1778    ///         },
1779    ///         "security": [],
1780    ///         "securityDefinitions": {},
1781    ///     })
1782    /// );
1783    /// ```
1784    fn property<F, T>(self, name: impl Into<String>, required: bool, f: F) -> Self
1785    where
1786        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
1787        DS: Extendable,
1788        T: Into<UncheckedDataSchema<DS, AS, OS>>;
1789}
1790
1791/// An interface for things behaving like a string data schema builder.
1792pub trait StringDataSchemaBuilderLike<DS, AS, OS> {
1793    opt_field_decl!(min_length: u32, max_length: u32);
1794
1795    opt_field_into_decl!(
1796        pattern: String,
1797        content_encoding: String,
1798        content_media_type: String,
1799    );
1800}
1801
1802macro_rules! opt_field_builder {
1803    ($($field:ident : $ty:ty),* $(,)?) => {
1804        $(
1805            fn $field(mut self, value: $ty) -> Self {
1806                self.$field = Some(value);
1807                self
1808            }
1809        )*
1810    };
1811}
1812
1813macro_rules! opt_field_into_builder {
1814    ($($field:ident : $ty:ty),* $(,)?) => {
1815        $(
1816            fn $field(mut self, value: impl Into<$ty>) -> Self {
1817                self.$field = Some(value.into());
1818                self
1819            }
1820        )*
1821    };
1822}
1823
1824impl<Inner, DS, AS, OS> TupleDataSchemaBuilderLike<DS, AS, OS>
1825    for TupleDataSchemaBuilder<Inner, DS, AS, OS>
1826where
1827    Inner: BuildableDataSchema<DS, AS, OS, Extended>,
1828{
1829    fn append<F, T>(mut self, f: F) -> Self
1830    where
1831        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
1832        DS: Extendable,
1833        T: Into<UncheckedDataSchema<DS, AS, OS>>,
1834    {
1835        self.items
1836            .push(f(DataSchemaBuilder::<DS, _, _, _>::empty()).into());
1837        self
1838    }
1839}
1840
1841impl<Inner, DS, AS, OS> VecDataSchemaBuilderLike<DS, AS, OS>
1842    for VecDataSchemaBuilder<Inner, DS, AS, OS>
1843where
1844    Inner: BuildableDataSchema<DS, AS, OS, Extended>,
1845{
1846    opt_field_builder!(min_items: u32, max_items: u32);
1847
1848    fn set_item<F, T>(mut self, f: F) -> Self
1849    where
1850        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
1851        DS: Extendable,
1852        T: Into<UncheckedDataSchema<DS, AS, OS>>,
1853    {
1854        self.item = Some(f(DataSchemaBuilder::<DS, _, _, _>::empty()).into());
1855        self
1856    }
1857}
1858
1859impl<Inner: BuildableDataSchema<DS, AS, OS, Extended>, DS, AS, OS>
1860    NumberDataSchemaBuilderLike<DS, AS, OS> for NumberDataSchemaBuilder<Inner>
1861{
1862    opt_field_builder!(multiple_of: f64);
1863
1864    fn minimum(mut self, value: f64) -> Self {
1865        self.minimum = Some(Minimum::Inclusive(value));
1866        self
1867    }
1868
1869    fn exclusive_minimum(mut self, value: f64) -> Self {
1870        self.minimum = Some(Minimum::Exclusive(value));
1871        self
1872    }
1873
1874    fn maximum(mut self, value: f64) -> Self {
1875        self.maximum = Some(Maximum::Inclusive(value));
1876        self
1877    }
1878
1879    fn exclusive_maximum(mut self, value: f64) -> Self {
1880        self.maximum = Some(Maximum::Exclusive(value));
1881        self
1882    }
1883}
1884
1885impl<Inner: BuildableDataSchema<DS, AS, OS, Extended>, DS, AS, OS>
1886    IntegerDataSchemaBuilderLike<DS, AS, OS> for IntegerDataSchemaBuilder<Inner>
1887{
1888    opt_field_builder!(multiple_of: NonZeroU64);
1889
1890    fn minimum(mut self, value: i64) -> Self {
1891        self.minimum = Some(Minimum::Inclusive(value));
1892        self
1893    }
1894
1895    fn exclusive_minimum(mut self, value: i64) -> Self {
1896        self.minimum = Some(Minimum::Exclusive(value));
1897        self
1898    }
1899
1900    fn maximum(mut self, value: i64) -> Self {
1901        self.maximum = Some(Maximum::Inclusive(value));
1902        self
1903    }
1904
1905    fn exclusive_maximum(mut self, value: i64) -> Self {
1906        self.maximum = Some(Maximum::Exclusive(value));
1907        self
1908    }
1909}
1910
1911impl<Inner, DS, AS, OS> ObjectDataSchemaBuilderLike<DS, AS, OS>
1912    for ObjectDataSchemaBuilder<Inner, DS, AS, OS>
1913where
1914    Inner: BuildableDataSchema<DS, AS, OS, Extended>,
1915{
1916    fn property<F, T>(mut self, name: impl Into<String>, required: bool, f: F) -> Self
1917    where
1918        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
1919        DS: Extendable,
1920        T: Into<UncheckedDataSchema<DS, AS, OS>>,
1921    {
1922        let data_schema = f(DataSchemaBuilder::<DS, _, _, _>::empty()).into();
1923        let name = name.into();
1924
1925        if required {
1926            self.required.push(name.clone());
1927        }
1928
1929        self.properties.push((name, data_schema));
1930        self
1931    }
1932}
1933
1934impl<Inner: BuildableDataSchema<DS, AS, OS, Extended>, DS, AS, OS>
1935    StringDataSchemaBuilderLike<DS, AS, OS> for StringDataSchemaBuilder<Inner>
1936{
1937    opt_field_builder!(min_length: u32, max_length: u32);
1938
1939    opt_field_into_builder!(
1940        pattern: String,
1941        content_encoding: String,
1942        content_media_type: String,
1943    );
1944}
1945
1946macro_rules! impl_inner_delegate_schema_builder_like_vec {
1947    ($inner:ident) => {
1948        #[inline]
1949        fn min_items(mut self, value: u32) -> Self {
1950            self.$inner = self.$inner.min_items(value);
1951            self
1952        }
1953
1954        #[inline]
1955        fn max_items(mut self, value: u32) -> Self {
1956            self.$inner = self.$inner.max_items(value);
1957            self
1958        }
1959
1960        #[inline]
1961        fn set_item<F, T>(mut self, f: F) -> Self
1962        where
1963            F: FnOnce(
1964                crate::builder::data_schema::DataSchemaBuilder<
1965                    <DS as Extendable>::Empty,
1966                    AS,
1967                    OS,
1968                    crate::builder::ToExtend,
1969                >,
1970            ) -> T,
1971            DS: Extendable,
1972            T: Into<crate::builder::data_schema::UncheckedDataSchema<DS, AS, OS>>,
1973        {
1974            self.$inner = self.$inner.set_item(f);
1975            self
1976        }
1977    };
1978}
1979
1980macro_rules! impl_inner_delegate_schema_builder_like_tuple {
1981    ($inner:ident) => {
1982        #[inline]
1983        fn append<F, T>(mut self, f: F) -> Self
1984        where
1985            F: FnOnce(
1986                crate::builder::data_schema::DataSchemaBuilder<
1987                    <DS as Extendable>::Empty,
1988                    AS,
1989                    OS,
1990                    crate::builder::ToExtend,
1991                >,
1992            ) -> T,
1993            DS: Extendable,
1994            T: Into<crate::builder::data_schema::UncheckedDataSchema<DS, AS, OS>>,
1995        {
1996            self.$inner = self.$inner.append(f);
1997            self
1998        }
1999    };
2000}
2001
2002macro_rules! impl_inner_delegate_schema_builder_like_number {
2003    ($inner:ident) => {
2004        #[inline]
2005        fn minimum(mut self, value: f64) -> Self {
2006            self.$inner = self.$inner.minimum(value);
2007            self
2008        }
2009
2010        #[inline]
2011        fn maximum(mut self, value: f64) -> Self {
2012            self.$inner = self.$inner.maximum(value);
2013            self
2014        }
2015
2016        #[inline]
2017        fn exclusive_minimum(mut self, value: f64) -> Self {
2018            self.$inner = self.$inner.exclusive_minimum(value);
2019            self
2020        }
2021
2022        #[inline]
2023        fn exclusive_maximum(mut self, value: f64) -> Self {
2024            self.$inner = self.$inner.exclusive_maximum(value);
2025            self
2026        }
2027
2028        #[inline]
2029        fn multiple_of(mut self, value: f64) -> Self {
2030            self.$inner = self.$inner.multiple_of(value);
2031            self
2032        }
2033    };
2034}
2035
2036macro_rules! impl_inner_delegate_schema_builder_like_integer {
2037    ($inner:ident) => {
2038        #[inline]
2039        fn minimum(mut self, value: i64) -> Self {
2040            self.$inner = self.$inner.minimum(value);
2041            self
2042        }
2043
2044        #[inline]
2045        fn maximum(mut self, value: i64) -> Self {
2046            self.$inner = self.$inner.maximum(value);
2047            self
2048        }
2049
2050        #[inline]
2051        fn exclusive_minimum(mut self, value: i64) -> Self {
2052            self.$inner = self.$inner.exclusive_minimum(value);
2053            self
2054        }
2055
2056        #[inline]
2057        fn exclusive_maximum(mut self, value: i64) -> Self {
2058            self.$inner = self.$inner.exclusive_maximum(value);
2059            self
2060        }
2061
2062        #[inline]
2063        fn multiple_of(mut self, value: core::num::NonZeroU64) -> Self {
2064            self.$inner = self.$inner.multiple_of(value);
2065            self
2066        }
2067    };
2068}
2069
2070macro_rules! impl_inner_delegate_schema_builder_like_object {
2071    ($inner:ident) => {
2072        #[inline]
2073        fn property<F, T>(mut self, name: impl Into<String>, required: bool, f: F) -> Self
2074        where
2075            F: FnOnce(
2076                crate::builder::data_schema::DataSchemaBuilder<
2077                    <DS as Extendable>::Empty,
2078                    AS,
2079                    OS,
2080                    crate::builder::ToExtend,
2081                >,
2082            ) -> T,
2083            DS: Extendable,
2084            T: Into<crate::builder::data_schema::UncheckedDataSchema<DS, AS, OS>>,
2085        {
2086            self.$inner = self.$inner.property(name, required, f);
2087            self
2088        }
2089    };
2090}
2091
2092macro_rules! impl_delegate_schema_builder_like {
2093    ($( $ty:ident <$( $generic:ident ),+> on $inner:ident ),+ $(,)?) => {
2094        $(
2095            impl<DS, AS, OS, $($generic: crate::builder::data_schema::VecDataSchemaBuilderLike<DS, AS, OS>),+ > crate::builder::data_schema::VecDataSchemaBuilderLike<DS, AS, OS> for $ty< $($generic),+ > {
2096                crate::builder::data_schema::impl_inner_delegate_schema_builder_like_vec!($inner);
2097            }
2098
2099            impl<DS, AS, OS, $($generic: crate::builder::data_schema::TupleDataSchemaBuilderLike<DS, AS, OS>),+ > crate::builder::data_schema::TupleDataSchemaBuilderLike<DS, AS, OS> for $ty< $($generic),+ > {
2100                crate::builder::data_schema::impl_inner_delegate_schema_builder_like_tuple!($inner);
2101            }
2102
2103            impl<DS, AS, OS, $($generic: crate::builder::data_schema::NumberDataSchemaBuilderLike<DS, AS, OS>),+ > crate::builder::data_schema::NumberDataSchemaBuilderLike<DS, AS, OS> for $ty< $($generic),+ > {
2104                crate::builder::data_schema::impl_inner_delegate_schema_builder_like_number!($inner);
2105            }
2106
2107            impl<DS, AS, OS, $($generic: crate::builder::data_schema::IntegerDataSchemaBuilderLike<DS, AS, OS>),+ > crate::builder::data_schema::IntegerDataSchemaBuilderLike<DS, AS, OS> for $ty< $($generic),+ > {
2108                crate::builder::data_schema::impl_inner_delegate_schema_builder_like_integer!($inner);
2109            }
2110
2111            impl<DS, AS, OS, $($generic: crate::builder::data_schema::ObjectDataSchemaBuilderLike<DS, AS, OS>),+ > crate::builder::data_schema::ObjectDataSchemaBuilderLike<DS, AS, OS> for $ty< $($generic),+ > {
2112                crate::builder::data_schema::impl_inner_delegate_schema_builder_like_object!($inner);
2113            }
2114        )+
2115    };
2116}
2117pub(super) use impl_delegate_schema_builder_like;
2118pub(super) use impl_inner_delegate_schema_builder_like_integer;
2119pub(super) use impl_inner_delegate_schema_builder_like_number;
2120pub(super) use impl_inner_delegate_schema_builder_like_object;
2121pub(super) use impl_inner_delegate_schema_builder_like_tuple;
2122pub(super) use impl_inner_delegate_schema_builder_like_vec;
2123
2124impl_delegate_schema_builder_like!(ReadOnly<Inner> on inner, WriteOnly<Innner> on inner);
2125
2126macro_rules! buildable_data_schema_delegate {
2127    ($self:ident . $field:ident -> $fn:ident($($arg:ident),*)) => {{
2128        $self.$field = $self.$field.$fn($($arg),*);
2129        $self
2130    }};
2131}
2132
2133macro_rules! impl_delegate_buildable_data_schema {
2134    () => {};
2135
2136    ($kind:ident <DS, AS, OS $(, $($ty:ident),+)?> : $inner:ident $(, $($rest:tt)*)?) => {
2137        impl <DS, AS, OS $(, $($ty),+)? > crate::builder::data_schema::BuildableDataSchema<DS, AS, OS, crate::builder::Extended> for $kind <$($($ty),+ ,)? DS, AS, OS>
2138        $(
2139            where
2140                $($ty: crate::builder::data_schema::BuildableDataSchema<DS, AS, OS, crate::builder::Extended>),+
2141        )?
2142        {
2143            #[inline]
2144            fn unit(mut self, value: impl Into<String>) -> Self {
2145                crate::builder::data_schema::buildable_data_schema_delegate!(self.$inner -> unit(value))
2146            }
2147
2148            #[inline]
2149            fn format(mut self, value: impl Into<String>) -> Self {
2150                crate::builder::data_schema::buildable_data_schema_delegate!(self.$inner -> format(value))
2151            }
2152
2153            #[inline]
2154            fn default_value(mut self, value: impl Into<Value>) -> Self {
2155                crate::builder::data_schema::buildable_data_schema_delegate!(self.$inner -> default_value(value))
2156            }
2157        }
2158
2159        $(
2160            crate::builder::data_schema::impl_delegate_buildable_data_schema!($($rest)*);
2161        )?
2162    };
2163
2164    ($kind:ident $(<$($ty:ident),+>)? : $inner:ident $(, $($rest:tt)*)?) => {
2165        impl <DS, AS, OS, $($($ty),+)? > crate::builder::data_schema::BuildableDataSchema<DS, AS, OS, crate::builder::Extended> for $kind $(<$($ty),+>)?
2166        $(
2167            where
2168                $($ty: crate::builder::data_schema::BuildableDataSchema<DS, AS, OS, crate::builder::Extended>),+
2169        )?
2170        {
2171            #[inline]
2172            fn unit(mut self, value: impl Into<String>) -> Self {
2173                crate::builder::data_schema::buildable_data_schema_delegate!(self.$inner -> unit(value))
2174            }
2175
2176            #[inline]
2177            fn format(mut self, value: impl Into<String>) -> Self {
2178                crate::builder::data_schema::buildable_data_schema_delegate!(self.$inner -> format(value))
2179            }
2180
2181            #[inline]
2182            fn default_value(mut self, value: impl Into<Value>) -> Self {
2183                crate::builder::data_schema::buildable_data_schema_delegate!(self.$inner -> default_value(value))
2184            }
2185        }
2186
2187        $(
2188            crate::builder::data_schema::impl_delegate_buildable_data_schema!($($rest)*);
2189        )?
2190    };
2191
2192    ($kind:ident $(<$($ty:ident),+>)? $(, $($rest:tt)*)? ) => {
2193        crate::builder::data_schema::impl_delegate_buildable_data_schema!($kind $(<$($ty),+>)?: inner $(, $($rest)*)?);
2194    };
2195}
2196
2197impl_delegate_buildable_data_schema!(
2198    TupleDataSchemaBuilder<DS, AS, OS, Inner>,
2199    VecDataSchemaBuilder<DS, AS, OS, Inner>,
2200    NumberDataSchemaBuilder<Inner>,
2201    IntegerDataSchemaBuilder<Inner>,
2202    ObjectDataSchemaBuilder<DS, AS, OS, Inner>,
2203    StringDataSchemaBuilder<Inner>,
2204    StatelessDataSchemaBuilder<Inner>,
2205    ReadOnly<Inner>,
2206    WriteOnly<Inner>,
2207    EnumDataSchemaBuilder<Inner>,
2208    OneOfDataSchemaBuilder<Inner>,
2209);
2210
2211impl<DS, AS, OS, Status> BuildableDataSchema<DS, AS, OS, Status>
2212    for DataSchemaBuilder<DS, AS, OS, Status>
2213{
2214    #[inline]
2215    fn unit(mut self, value: impl Into<String>) -> Self {
2216        buildable_data_schema_delegate!(self.partial -> unit(value))
2217    }
2218
2219    #[inline]
2220    fn format(mut self, value: impl Into<String>) -> Self {
2221        buildable_data_schema_delegate!(self.partial-> format(value))
2222    }
2223
2224    #[inline]
2225    fn default_value(mut self, value: impl Into<Value>) -> Self {
2226        buildable_data_schema_delegate!(self.partial -> default_value(value))
2227    }
2228}
2229
2230pub(crate) use buildable_data_schema_delegate;
2231pub(crate) use impl_delegate_buildable_data_schema;
2232use serde_json::Value;
2233
2234macro_rules! trait_opt_field_builder {
2235    ($($field:ident : $ty:ty),* $(,)?) => {
2236        $(
2237            fn $field(mut self, value: impl Into<$ty>) -> Self {
2238                self.$field = Some(value.into());
2239                self
2240            }
2241        )*
2242    };
2243}
2244
2245impl_delegate_buildable_hr_info! (
2246    DataSchemaBuilder<DS, AS, OS, Status> on info,
2247);
2248
2249impl<DS, AS, OS, Status> BuildableDataSchema<DS, AS, OS, Status>
2250    for PartialDataSchemaBuilder<DS, AS, OS, Status>
2251{
2252    trait_opt_field_builder!(unit: String, format: String);
2253
2254    fn default_value(mut self, value: impl Into<Value>) -> Self {
2255        self.default = Some(value.into());
2256        self
2257    }
2258}
2259
2260impl_delegate_buildable_hr_info!(
2261    TupleDataSchemaBuilder<Inner: BuildableHumanReadableInfo, DS, AS, OS> on inner,
2262    VecDataSchemaBuilder<Inner: BuildableHumanReadableInfo, DS, AS, OS> on inner,
2263    NumberDataSchemaBuilder<Inner: BuildableHumanReadableInfo> on inner,
2264    IntegerDataSchemaBuilder<Inner: BuildableHumanReadableInfo> on inner,
2265    ObjectDataSchemaBuilder<Inner: BuildableHumanReadableInfo, DS, AS, OS> on inner,
2266    StringDataSchemaBuilder<Inner: BuildableHumanReadableInfo> on inner,
2267    EnumDataSchemaBuilder<Inner: BuildableHumanReadableInfo> on inner,
2268    OneOfDataSchemaBuilder<Inner: BuildableHumanReadableInfo> on inner,
2269    StatelessDataSchemaBuilder<Inner: BuildableHumanReadableInfo> on inner,
2270    ReadOnly<Inner: BuildableHumanReadableInfo> on inner,
2271    WriteOnly<Inner: BuildableHumanReadableInfo> on inner,
2272);
2273
2274macro_rules! impl_specializable_data_schema {
2275    ($($ty:ty $( : $($inner_path:ident).+ )? ),+ $(,)?) => {
2276        $(
2277            impl<DS, AS, OS> SpecializableDataSchema<DS, AS, OS> for $ty {
2278                type Stateless = StatelessDataSchemaBuilder<Self>;
2279                type Tuple = TupleDataSchemaBuilder<Self, DS, AS, OS>;
2280                type Vec = VecDataSchemaBuilder<Self, DS, AS, OS>;
2281                type Number = NumberDataSchemaBuilder<Self>;
2282                type Integer = IntegerDataSchemaBuilder<Self>;
2283                type Object = ObjectDataSchemaBuilder<Self, DS, AS, OS>;
2284                type String = StringDataSchemaBuilder<Self>;
2285                type Constant = ReadOnly<StatelessDataSchemaBuilder<Self>>;
2286
2287                fn tuple(self) -> Self::Tuple
2288                where
2289                    AS: Default
2290                {
2291                    TupleDataSchemaBuilder {
2292                        inner: self,
2293                        items: Default::default(),
2294                        other: Default::default(),
2295                    }
2296                }
2297
2298                fn tuple_ext<F>(self, f: F) -> Self::Tuple
2299                where
2300                    F: FnOnce(AS::Empty) -> AS,
2301                    AS: Extendable,
2302                {
2303                    let other = f(AS::empty());
2304
2305                    TupleDataSchemaBuilder {
2306                        inner: self,
2307                        items: Default::default(),
2308                        other,
2309                    }
2310                }
2311
2312                fn vec(self) -> Self::Vec
2313                where
2314                    AS: Default
2315                {
2316                    VecDataSchemaBuilder {
2317                        inner: self,
2318                        item: Default::default(),
2319                        min_items: Default::default(),
2320                        max_items: Default::default(),
2321                        other: Default::default(),
2322                    }
2323                }
2324
2325                fn vec_ext<F>(self, f: F) -> Self::Vec
2326                where
2327                    F: FnOnce(AS::Empty) -> AS,
2328                    AS: Extendable,
2329                {
2330                    let other = f(AS::empty());
2331
2332                    VecDataSchemaBuilder {
2333                        inner: self,
2334                        item: Default::default(),
2335                        min_items: Default::default(),
2336                        max_items: Default::default(),
2337                        other,
2338                    }
2339                }
2340
2341                fn bool(self) -> Self::Stateless {
2342                    StatelessDataSchemaBuilder {
2343                        inner: self,
2344                        ty: Some(StatelessDataSchemaType::Boolean),
2345                    }
2346                }
2347
2348                fn number(self) -> Self::Number {
2349                    NumberDataSchemaBuilder {
2350                        inner: self,
2351                        maximum: Default::default(),
2352                        minimum: Default::default(),
2353                        multiple_of: Default::default(),
2354                    }
2355                }
2356
2357                fn integer(self) -> Self::Integer {
2358                    IntegerDataSchemaBuilder {
2359                        inner: self,
2360                        maximum: Default::default(),
2361                        minimum: Default::default(),
2362                        multiple_of: Default::default(),
2363                    }
2364                }
2365
2366                fn object(self) -> Self::Object
2367                where
2368                    OS: Default
2369                {
2370                    ObjectDataSchemaBuilder {
2371                        inner: self,
2372                        properties: Default::default(),
2373                        required: Default::default(),
2374                        other: Default::default(),
2375                    }
2376                }
2377
2378                fn object_ext<F>(self, f: F) -> Self::Object
2379                where
2380                    F: FnOnce(OS::Empty) -> OS,
2381                    OS: Extendable,
2382                {
2383                    let other = f(OS::empty());
2384
2385                    ObjectDataSchemaBuilder {
2386                        inner: self,
2387                        properties: Default::default(),
2388                        required: Default::default(),
2389                        other,
2390                    }
2391                }
2392
2393                fn string(self) -> Self::String {
2394                    StringDataSchemaBuilder {
2395                        inner: self,
2396                        min_length: Default::default(),
2397                        max_length: Default::default(),
2398                        pattern: Default::default(),
2399                        content_encoding: Default::default(),
2400                        content_media_type: Default::default(),
2401                    }
2402                }
2403
2404                fn null(self) -> Self::Stateless {
2405                    StatelessDataSchemaBuilder {
2406                        inner: self,
2407                        ty: Some(StatelessDataSchemaType::Null),
2408                    }
2409                }
2410
2411                fn constant(mut self, value: impl Into<Value>) -> Self::Constant {
2412                    self $(. $($inner_path).+)?.constant = Some(value.into());
2413                    ReadOnly {
2414                        inner: StatelessDataSchemaBuilder {
2415                            inner: self,
2416                            ty: None,
2417                        },
2418                    }
2419                }
2420            }
2421        )+
2422    };
2423}
2424
2425impl_specializable_data_schema!(PartialDataSchemaBuilder<DS, AS, OS, Extended>, DataSchemaBuilder<DS, AS, OS, Extended>: partial);
2426
2427macro_rules! impl_enumerable_data_schema {
2428    ($($ty:ty $( : $($inner_path:ident).+ )? ),+ $(,)?) => {
2429        $(
2430        impl<DS, AS, OS> EnumerableDataSchema<DS, AS, OS, Extended> for $ty {
2431            type Target = EnumDataSchemaBuilder<Self>;
2432
2433            fn enumeration(mut self, value: impl Into<Value>) -> EnumDataSchemaBuilder<Self> {
2434                self $(. $($inner_path).+ )?.enumeration.push(value.into());
2435                EnumDataSchemaBuilder { inner: self }
2436            }
2437        }
2438        )+
2439    };
2440}
2441
2442impl_enumerable_data_schema!(PartialDataSchemaBuilder<DS, AS, OS, Extended>, DataSchemaBuilder<DS, AS, OS, Extended>: partial);
2443
2444impl<Inner, DS, AS, OS> EnumerableDataSchema<DS, AS, OS, Extended> for ReadOnly<Inner>
2445where
2446    Inner: EnumerableDataSchema<DS, AS, OS, Extended>,
2447{
2448    type Target = ReadOnly<Inner::Target>;
2449
2450    #[inline]
2451    fn enumeration(self, value: impl Into<Value>) -> Self::Target {
2452        let Self { inner } = self;
2453
2454        let inner = inner.enumeration(value);
2455        ReadOnly { inner }
2456    }
2457}
2458
2459impl<Inner, DS, AS, OS> EnumerableDataSchema<DS, AS, OS, Extended> for WriteOnly<Inner>
2460where
2461    Inner: EnumerableDataSchema<DS, AS, OS, Extended>,
2462{
2463    type Target = WriteOnly<Inner::Target>;
2464
2465    #[inline]
2466    fn enumeration(self, value: impl Into<Value>) -> Self::Target {
2467        let Self { inner } = self;
2468
2469        let inner = inner.enumeration(value);
2470        WriteOnly { inner }
2471    }
2472}
2473
2474impl<DS, AS, OS> EnumerableDataSchema<DS, AS, OS, Extended>
2475    for EnumDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>>
2476{
2477    type Target = Self;
2478
2479    #[inline]
2480    fn enumeration(mut self, value: impl Into<Value>) -> Self::Target {
2481        self.inner.enumeration.push(value.into());
2482        self
2483    }
2484}
2485
2486impl<DS, AS, OS> EnumerableDataSchema<DS, AS, OS, Extended>
2487    for EnumDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>>
2488{
2489    type Target = Self;
2490
2491    #[inline]
2492    fn enumeration(mut self, value: impl Into<Value>) -> Self::Target {
2493        self.inner.partial.enumeration.push(value.into());
2494        self
2495    }
2496}
2497
2498macro_rules! impl_union_data_schema {
2499    ($($ty:ty $( : $($inner_path:ident).+ )? ),+ $(,)?) => {
2500        $(
2501            impl<DS, AS, OS> UnionDataSchema<DS, AS, OS> for $ty
2502            {
2503                type Target = OneOfDataSchemaBuilder<Self>;
2504
2505                fn one_of<F, T>(mut self, f: F) -> Self::Target
2506                where
2507                    F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
2508                    DS: Extendable,
2509                    T: Into<UncheckedDataSchema<DS, AS, OS>>,
2510                {
2511                    self $(. $($inner_path).+ )? .one_of.push(f(DataSchemaBuilder::<DS, _, _, _>::empty()).into());
2512                    OneOfDataSchemaBuilder { inner: self }
2513                }
2514            }
2515        )+
2516    };
2517}
2518
2519impl_union_data_schema!(PartialDataSchemaBuilder<DS, AS, OS, Extended>, DataSchemaBuilder<DS, AS, OS, Extended>: partial);
2520
2521impl<Inner, DS, AS, OS> UnionDataSchema<DS, AS, OS> for ReadOnly<Inner>
2522where
2523    Inner: UnionDataSchema<DS, AS, OS>,
2524{
2525    type Target = ReadOnly<Inner::Target>;
2526
2527    fn one_of<F, T>(self, f: F) -> Self::Target
2528    where
2529        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
2530        DS: Extendable,
2531        T: Into<UncheckedDataSchema<DS, AS, OS>>,
2532    {
2533        let Self { inner } = self;
2534        let inner = inner.one_of(f);
2535        ReadOnly { inner }
2536    }
2537}
2538
2539impl<Inner, DS, AS, OS> UnionDataSchema<DS, AS, OS> for WriteOnly<Inner>
2540where
2541    Inner: UnionDataSchema<DS, AS, OS>,
2542{
2543    type Target = WriteOnly<Inner::Target>;
2544
2545    fn one_of<F, T>(self, f: F) -> Self::Target
2546    where
2547        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
2548        DS: Extendable,
2549        T: Into<UncheckedDataSchema<DS, AS, OS>>,
2550    {
2551        let Self { inner } = self;
2552        let inner = inner.one_of(f);
2553        WriteOnly { inner }
2554    }
2555}
2556
2557impl<DS, AS, OS> UnionDataSchema<DS, AS, OS>
2558    for OneOfDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>>
2559{
2560    type Target = Self;
2561
2562    fn one_of<F, T>(mut self, f: F) -> Self::Target
2563    where
2564        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
2565        DS: Extendable,
2566        T: Into<UncheckedDataSchema<DS, AS, OS>>,
2567    {
2568        self.inner
2569            .one_of
2570            .push(f(DataSchemaBuilder::<DS, _, _, _>::empty()).into());
2571        self
2572    }
2573}
2574
2575impl<DS, AS, OS> UnionDataSchema<DS, AS, OS>
2576    for OneOfDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>>
2577{
2578    type Target = Self;
2579
2580    fn one_of<F, T>(mut self, f: F) -> Self::Target
2581    where
2582        F: FnOnce(DataSchemaBuilder<<DS as Extendable>::Empty, AS, OS, ToExtend>) -> T,
2583        DS: Extendable,
2584        T: Into<UncheckedDataSchema<DS, AS, OS>>,
2585    {
2586        self.inner
2587            .partial
2588            .one_of
2589            .push(f(DataSchemaBuilder::<DS, _, _, _>::empty()).into());
2590        self
2591    }
2592}
2593
2594macro_rules! impl_rw_data_schema {
2595    ($( $ty:ty; $($inner_path:ident).+ ),+ $(,)?) => {
2596        $(
2597            impl<DS, AS, OS> ReadableWriteableDataSchema<DS, AS, OS, Extended> for $ty
2598            {
2599                type ReadOnly = ReadOnly<Self>;
2600                type WriteOnly = WriteOnly<Self>;
2601
2602                #[inline]
2603                fn read_only(mut self) -> Self::ReadOnly {
2604                    self.$($inner_path).+.read_only = true;
2605                    ReadOnly {
2606                        inner: self,
2607                    }
2608                }
2609
2610                #[inline]
2611                fn write_only(mut self) -> Self::WriteOnly {
2612                    self.$($inner_path).+.write_only = true;
2613                    WriteOnly {
2614                        inner: self,
2615                    }
2616                }
2617            }
2618        )+
2619    };
2620}
2621
2622impl_rw_data_schema!(
2623    StatelessDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>>; inner.partial,
2624    StatelessDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>>; inner,
2625    TupleDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>, DS, AS, OS>; inner.partial,
2626    TupleDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>, DS, AS, OS>; inner,
2627    VecDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>, DS, AS, OS>; inner.partial,
2628    VecDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>, DS, AS, OS>; inner,
2629    NumberDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>>; inner.partial,
2630    NumberDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>>; inner,
2631    IntegerDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>>; inner.partial,
2632    IntegerDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>>; inner,
2633    ObjectDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>, DS, AS, OS>; inner.partial,
2634    ObjectDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>, DS, AS, OS>; inner,
2635    StringDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>>; inner.partial,
2636    StringDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>>; inner,
2637    EnumDataSchemaBuilder<DataSchemaBuilder<DS, AS, OS, Extended>>; inner.partial,
2638    EnumDataSchemaBuilder<PartialDataSchemaBuilder<DS, AS, OS, Extended>>; inner,
2639);
2640
2641impl<T, DS, AS, OS> From<ReadOnly<T>> for DataSchemaBuilder<DS, AS, OS, Extended>
2642where
2643    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2644{
2645    fn from(data_schema: ReadOnly<T>) -> Self {
2646        let DataSchemaBuilder { mut partial, info } = data_schema.inner.into();
2647        partial.read_only = true;
2648
2649        Self { partial, info }
2650    }
2651}
2652
2653impl<T, DS, AS, OS> From<WriteOnly<T>> for DataSchemaBuilder<DS, AS, OS, Extended>
2654where
2655    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2656{
2657    fn from(data_schema: WriteOnly<T>) -> Self {
2658        let DataSchemaBuilder { mut partial, info } = data_schema.inner.into();
2659        partial.write_only = true;
2660
2661        Self { partial, info }
2662    }
2663}
2664
2665impl<T, DS, AS, OS> From<ReadOnly<T>> for PartialDataSchemaBuilder<DS, AS, OS, Extended>
2666where
2667    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
2668{
2669    fn from(data_schema: ReadOnly<T>) -> Self {
2670        let mut data_schema = data_schema.inner.into();
2671        data_schema.read_only = true;
2672        data_schema
2673    }
2674}
2675
2676impl<T, DS, AS, OS> From<WriteOnly<T>> for PartialDataSchemaBuilder<DS, AS, OS, Extended>
2677where
2678    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
2679{
2680    fn from(data_schema: WriteOnly<T>) -> Self {
2681        let mut data_schema = data_schema.inner.into();
2682        data_schema.write_only = true;
2683        data_schema
2684    }
2685}
2686
2687impl<DS, AS, OS> From<StatelessDataSchemaType> for UncheckedDataSchemaSubtype<DS, AS, OS> {
2688    fn from(ty: StatelessDataSchemaType) -> Self {
2689        match ty {
2690            StatelessDataSchemaType::Boolean => UncheckedDataSchemaSubtype::Boolean,
2691            StatelessDataSchemaType::Null => UncheckedDataSchemaSubtype::Null,
2692        }
2693    }
2694}
2695
2696impl<T, DS, AS, OS> From<StatelessDataSchemaBuilder<T>> for UncheckedDataSchema<DS, AS, OS>
2697where
2698    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2699{
2700    fn from(builder: StatelessDataSchemaBuilder<T>) -> Self {
2701        let StatelessDataSchemaBuilder { inner, ty } = builder;
2702        let DataSchemaBuilder {
2703            partial:
2704                PartialDataSchemaBuilder {
2705                    constant,
2706                    default,
2707                    unit,
2708                    one_of: _,
2709                    enumeration: _,
2710                    read_only,
2711                    write_only,
2712                    format,
2713                    other,
2714                    _marker: _,
2715                },
2716            info:
2717                HumanReadableInfo {
2718                    attype,
2719                    title,
2720                    titles,
2721                    description,
2722                    descriptions,
2723                },
2724        } = inner.into();
2725
2726        let subtype = ty.map(Into::into);
2727
2728        UncheckedDataSchema {
2729            attype,
2730            title,
2731            titles,
2732            description,
2733            descriptions,
2734            constant,
2735            default,
2736            unit,
2737            one_of: None,
2738            enumeration: None,
2739            read_only,
2740            write_only,
2741            format,
2742            subtype,
2743            other,
2744        }
2745    }
2746}
2747
2748impl<T, DS, AS, OS> TryFrom<StatelessDataSchemaBuilder<T>> for DataSchema<DS, AS, OS>
2749where
2750    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2751{
2752    type Error = Error;
2753
2754    fn try_from(value: StatelessDataSchemaBuilder<T>) -> Result<Self, Self::Error> {
2755        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
2756        data_schema.try_into()
2757    }
2758}
2759
2760impl<T, DS, AS, OS> From<StatelessDataSchemaBuilder<T>> for PartialDataSchema<DS, AS, OS>
2761where
2762    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
2763{
2764    fn from(builder: StatelessDataSchemaBuilder<T>) -> Self {
2765        let StatelessDataSchemaBuilder { inner, ty } = builder;
2766        let PartialDataSchemaBuilder {
2767            constant,
2768            default,
2769            unit,
2770            one_of: _,
2771            enumeration: _,
2772            read_only,
2773            write_only,
2774            format,
2775            other,
2776            _marker: _,
2777        } = inner.into();
2778
2779        let subtype = ty.map(Into::into);
2780
2781        PartialDataSchema {
2782            constant,
2783            default,
2784            unit,
2785            one_of: None,
2786            enumeration: None,
2787            read_only,
2788            write_only,
2789            format,
2790            subtype,
2791            other,
2792        }
2793    }
2794}
2795
2796impl<T, DS, AS, OS> From<TupleDataSchemaBuilder<T, DS, AS, OS>> for UncheckedDataSchema<DS, AS, OS>
2797where
2798    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2799{
2800    fn from(builder: TupleDataSchemaBuilder<T, DS, AS, OS>) -> Self {
2801        let TupleDataSchemaBuilder {
2802            inner,
2803            items,
2804            other: other_array_schema,
2805        } = builder;
2806        let DataSchemaBuilder {
2807            partial:
2808                PartialDataSchemaBuilder {
2809                    constant: _,
2810                    default,
2811                    unit,
2812                    one_of: _,
2813                    enumeration: _,
2814                    read_only,
2815                    write_only,
2816                    format,
2817                    other: other_data_schema,
2818                    _marker: _,
2819                },
2820            info:
2821                HumanReadableInfo {
2822                    attype,
2823                    title,
2824                    titles,
2825                    description,
2826                    descriptions,
2827                },
2828        } = inner.into();
2829
2830        let items = Some(BoxedElemOrVec::Vec(items));
2831        let subtype = Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
2832            items,
2833            min_items: None,
2834            max_items: None,
2835            other: other_array_schema,
2836        }));
2837
2838        UncheckedDataSchema {
2839            attype,
2840            title,
2841            titles,
2842            description,
2843            descriptions,
2844            constant: None,
2845            default,
2846            unit,
2847            one_of: None,
2848            enumeration: None,
2849            read_only,
2850            write_only,
2851            format,
2852            subtype,
2853            other: other_data_schema,
2854        }
2855    }
2856}
2857
2858impl<T, DS, AS, OS> From<VecDataSchemaBuilder<T, DS, AS, OS>> for UncheckedDataSchema<DS, AS, OS>
2859where
2860    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2861{
2862    fn from(builder: VecDataSchemaBuilder<T, DS, AS, OS>) -> Self {
2863        let VecDataSchemaBuilder {
2864            inner,
2865            item,
2866            min_items,
2867            max_items,
2868            other: other_array_schema,
2869        } = builder;
2870        let DataSchemaBuilder {
2871            partial:
2872                PartialDataSchemaBuilder {
2873                    constant: _,
2874                    default,
2875                    unit,
2876                    one_of: _,
2877                    enumeration: _,
2878                    read_only,
2879                    write_only,
2880                    format,
2881                    other: other_data_schema,
2882                    _marker: _,
2883                },
2884            info:
2885                HumanReadableInfo {
2886                    attype,
2887                    title,
2888                    titles,
2889                    description,
2890                    descriptions,
2891                },
2892        } = inner.into();
2893
2894        let items = item.map(|item| BoxedElemOrVec::Elem(Box::new(item)));
2895        let subtype = Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
2896            items,
2897            min_items,
2898            max_items,
2899            other: other_array_schema,
2900        }));
2901
2902        UncheckedDataSchema {
2903            attype,
2904            title,
2905            titles,
2906            description,
2907            descriptions,
2908            constant: None,
2909            default,
2910            unit,
2911            one_of: None,
2912            enumeration: None,
2913            read_only,
2914            write_only,
2915            format,
2916            subtype,
2917            other: other_data_schema,
2918        }
2919    }
2920}
2921
2922impl<T, DS, AS, OS> TryFrom<TupleDataSchemaBuilder<T, DS, AS, OS>> for DataSchema<DS, AS, OS>
2923where
2924    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2925{
2926    type Error = Error;
2927
2928    fn try_from(value: TupleDataSchemaBuilder<T, DS, AS, OS>) -> Result<Self, Self::Error> {
2929        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
2930        data_schema.try_into()
2931    }
2932}
2933
2934impl<T, DS, AS, OS> TryFrom<VecDataSchemaBuilder<T, DS, AS, OS>> for DataSchema<DS, AS, OS>
2935where
2936    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
2937{
2938    type Error = Error;
2939
2940    fn try_from(value: VecDataSchemaBuilder<T, DS, AS, OS>) -> Result<Self, Self::Error> {
2941        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
2942        data_schema.try_into()
2943    }
2944}
2945
2946impl<T, DS, AS, OS> From<TupleDataSchemaBuilder<T, DS, AS, OS>> for PartialDataSchema<DS, AS, OS>
2947where
2948    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
2949{
2950    fn from(builder: TupleDataSchemaBuilder<T, DS, AS, OS>) -> Self {
2951        let TupleDataSchemaBuilder {
2952            inner,
2953            items,
2954            other: other_array_schema,
2955        } = builder;
2956        let PartialDataSchemaBuilder {
2957            constant: _,
2958            default,
2959            unit,
2960            one_of: _,
2961            enumeration: _,
2962            read_only,
2963            write_only,
2964            format,
2965            other: other_data_schema,
2966            _marker: _,
2967        } = inner.into();
2968
2969        let items = Some(BoxedElemOrVec::Vec(items));
2970        let subtype = Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
2971            items,
2972            min_items: None,
2973            max_items: None,
2974            other: other_array_schema,
2975        }));
2976
2977        PartialDataSchema {
2978            constant: None,
2979            default,
2980            unit,
2981            one_of: None,
2982            enumeration: None,
2983            read_only,
2984            write_only,
2985            format,
2986            subtype,
2987            other: other_data_schema,
2988        }
2989    }
2990}
2991
2992impl<T, DS, AS, OS> From<VecDataSchemaBuilder<T, DS, AS, OS>> for PartialDataSchema<DS, AS, OS>
2993where
2994    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
2995{
2996    fn from(builder: VecDataSchemaBuilder<T, DS, AS, OS>) -> Self {
2997        let VecDataSchemaBuilder {
2998            inner,
2999            item,
3000            min_items,
3001            max_items,
3002            other: other_array_schema,
3003        } = builder;
3004        let PartialDataSchemaBuilder {
3005            constant: _,
3006            default,
3007            unit,
3008            one_of: _,
3009            enumeration: _,
3010            read_only,
3011            write_only,
3012            format,
3013            other: other_data_schema,
3014            _marker: _,
3015        } = inner.into();
3016
3017        let items = item.map(|item| BoxedElemOrVec::Elem(Box::new(item)));
3018        let subtype = Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
3019            items,
3020            min_items,
3021            max_items,
3022            other: other_array_schema,
3023        }));
3024
3025        PartialDataSchema {
3026            constant: None,
3027            default,
3028            unit,
3029            one_of: None,
3030            enumeration: None,
3031            read_only,
3032            write_only,
3033            format,
3034            subtype,
3035            other: other_data_schema,
3036        }
3037    }
3038}
3039
3040impl<T, DS, AS, OS> From<NumberDataSchemaBuilder<T>> for UncheckedDataSchema<DS, AS, OS>
3041where
3042    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3043{
3044    fn from(builder: NumberDataSchemaBuilder<T>) -> Self {
3045        let NumberDataSchemaBuilder {
3046            inner,
3047            maximum,
3048            minimum,
3049            multiple_of,
3050        } = builder;
3051        let DataSchemaBuilder {
3052            partial:
3053                PartialDataSchemaBuilder {
3054                    constant: _,
3055                    default,
3056                    unit,
3057                    one_of: _,
3058                    enumeration: _,
3059                    read_only,
3060                    write_only,
3061                    format,
3062                    other,
3063                    _marker: _,
3064                },
3065            info:
3066                HumanReadableInfo {
3067                    attype,
3068                    title,
3069                    titles,
3070                    description,
3071                    descriptions,
3072                },
3073        } = inner.into();
3074
3075        let subtype = Some(UncheckedDataSchemaSubtype::Number(NumberSchema {
3076            minimum,
3077            maximum,
3078            multiple_of,
3079        }));
3080
3081        UncheckedDataSchema {
3082            attype,
3083            title,
3084            titles,
3085            description,
3086            descriptions,
3087            constant: None,
3088            default,
3089            unit,
3090            one_of: None,
3091            enumeration: None,
3092            read_only,
3093            write_only,
3094            format,
3095            subtype,
3096            other,
3097        }
3098    }
3099}
3100
3101impl<T, DS, AS, OS> TryFrom<NumberDataSchemaBuilder<T>> for DataSchema<DS, AS, OS>
3102where
3103    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3104{
3105    type Error = Error;
3106
3107    fn try_from(value: NumberDataSchemaBuilder<T>) -> Result<Self, Self::Error> {
3108        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3109        data_schema.try_into()
3110    }
3111}
3112
3113impl<T, DS, AS, OS> From<NumberDataSchemaBuilder<T>> for PartialDataSchema<DS, AS, OS>
3114where
3115    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
3116{
3117    fn from(builder: NumberDataSchemaBuilder<T>) -> Self {
3118        let NumberDataSchemaBuilder {
3119            inner,
3120            maximum,
3121            minimum,
3122            multiple_of,
3123        } = builder;
3124        let PartialDataSchemaBuilder {
3125            constant: _,
3126            default,
3127            unit,
3128            one_of: _,
3129            enumeration: _,
3130            read_only,
3131            write_only,
3132            format,
3133            other,
3134            _marker: _,
3135        } = inner.into();
3136
3137        let subtype = Some(UncheckedDataSchemaSubtype::Number(NumberSchema {
3138            minimum,
3139            maximum,
3140            multiple_of,
3141        }));
3142
3143        PartialDataSchema {
3144            constant: None,
3145            default,
3146            unit,
3147            one_of: None,
3148            enumeration: None,
3149            read_only,
3150            write_only,
3151            format,
3152            subtype,
3153            other,
3154        }
3155    }
3156}
3157
3158impl<T, DS, AS, OS> From<IntegerDataSchemaBuilder<T>> for UncheckedDataSchema<DS, AS, OS>
3159where
3160    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3161{
3162    fn from(builder: IntegerDataSchemaBuilder<T>) -> Self {
3163        let IntegerDataSchemaBuilder {
3164            inner,
3165            maximum,
3166            minimum,
3167            multiple_of,
3168        } = builder;
3169        let DataSchemaBuilder {
3170            partial:
3171                PartialDataSchemaBuilder {
3172                    constant: _,
3173                    default,
3174                    unit,
3175                    one_of: _,
3176                    enumeration: _,
3177                    read_only,
3178                    write_only,
3179                    format,
3180                    other,
3181                    _marker: _,
3182                },
3183            info:
3184                HumanReadableInfo {
3185                    attype,
3186                    title,
3187                    titles,
3188                    description,
3189                    descriptions,
3190                },
3191        } = inner.into();
3192
3193        let subtype = Some(UncheckedDataSchemaSubtype::Integer(IntegerSchema {
3194            minimum,
3195            maximum,
3196            multiple_of,
3197        }));
3198
3199        UncheckedDataSchema {
3200            attype,
3201            title,
3202            titles,
3203            description,
3204            descriptions,
3205            constant: None,
3206            default,
3207            unit,
3208            one_of: None,
3209            enumeration: None,
3210            read_only,
3211            write_only,
3212            format,
3213            subtype,
3214            other,
3215        }
3216    }
3217}
3218
3219impl<T, DS, AS, OS> TryFrom<IntegerDataSchemaBuilder<T>> for DataSchema<DS, AS, OS>
3220where
3221    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3222{
3223    type Error = Error;
3224
3225    fn try_from(value: IntegerDataSchemaBuilder<T>) -> Result<Self, Self::Error> {
3226        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3227        data_schema.try_into()
3228    }
3229}
3230
3231impl<T, DS, AS, OS> From<IntegerDataSchemaBuilder<T>> for PartialDataSchema<DS, AS, OS>
3232where
3233    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
3234{
3235    fn from(builder: IntegerDataSchemaBuilder<T>) -> Self {
3236        let IntegerDataSchemaBuilder {
3237            inner,
3238            maximum,
3239            minimum,
3240            multiple_of,
3241        } = builder;
3242        let PartialDataSchemaBuilder {
3243            constant: _,
3244            default,
3245            unit,
3246            one_of: _,
3247            enumeration: _,
3248            read_only,
3249            write_only,
3250            format,
3251            other,
3252            _marker: _,
3253        } = inner.into();
3254
3255        let subtype = Some(UncheckedDataSchemaSubtype::Integer(IntegerSchema {
3256            minimum,
3257            maximum,
3258            multiple_of,
3259        }));
3260
3261        PartialDataSchema {
3262            constant: None,
3263            default,
3264            unit,
3265            one_of: None,
3266            enumeration: None,
3267            read_only,
3268            write_only,
3269            format,
3270            subtype,
3271            other,
3272        }
3273    }
3274}
3275
3276impl<T, DS, AS, OS> From<ObjectDataSchemaBuilder<T, DS, AS, OS>> for UncheckedDataSchema<DS, AS, OS>
3277where
3278    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3279{
3280    fn from(builder: ObjectDataSchemaBuilder<T, DS, AS, OS>) -> Self {
3281        let ObjectDataSchemaBuilder {
3282            inner,
3283            properties,
3284            required,
3285            other: other_object_schema,
3286        } = builder;
3287        let DataSchemaBuilder {
3288            partial:
3289                PartialDataSchemaBuilder {
3290                    constant: _,
3291                    default,
3292                    unit,
3293                    one_of: _,
3294                    enumeration: _,
3295                    read_only,
3296                    write_only,
3297                    format,
3298                    other: other_data_schema,
3299                    _marker: _,
3300                },
3301            info:
3302                HumanReadableInfo {
3303                    attype,
3304                    title,
3305                    titles,
3306                    description,
3307                    descriptions,
3308                },
3309        } = inner.into();
3310
3311        let properties = properties
3312            .is_empty()
3313            .not()
3314            .then(|| properties.into_iter().collect());
3315        let required = required.is_empty().not().then_some(required);
3316        let subtype = Some(UncheckedDataSchemaSubtype::Object(UncheckedObjectSchema {
3317            properties,
3318            required,
3319            other: other_object_schema,
3320        }));
3321
3322        UncheckedDataSchema {
3323            attype,
3324            title,
3325            titles,
3326            description,
3327            descriptions,
3328            constant: None,
3329            default,
3330            unit,
3331            one_of: None,
3332            enumeration: None,
3333            read_only,
3334            write_only,
3335            format,
3336            subtype,
3337            other: other_data_schema,
3338        }
3339    }
3340}
3341
3342impl<T, DS, AS, OS> TryFrom<ObjectDataSchemaBuilder<T, DS, AS, OS>> for DataSchema<DS, AS, OS>
3343where
3344    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3345{
3346    type Error = Error;
3347
3348    fn try_from(value: ObjectDataSchemaBuilder<T, DS, AS, OS>) -> Result<Self, Self::Error> {
3349        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3350        data_schema.try_into()
3351    }
3352}
3353
3354impl<T, DS, AS, OS> From<ObjectDataSchemaBuilder<T, DS, AS, OS>> for PartialDataSchema<DS, AS, OS>
3355where
3356    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
3357{
3358    fn from(builder: ObjectDataSchemaBuilder<T, DS, AS, OS>) -> Self {
3359        let ObjectDataSchemaBuilder {
3360            inner,
3361            properties,
3362            required,
3363            other: other_object_schema,
3364        } = builder;
3365        let PartialDataSchemaBuilder {
3366            constant: _,
3367            default,
3368            unit,
3369            one_of: _,
3370            enumeration: _,
3371            read_only,
3372            write_only,
3373            format,
3374            other: other_data_schema,
3375            _marker: _,
3376        } = inner.into();
3377
3378        let properties = properties
3379            .is_empty()
3380            .not()
3381            .then(|| properties.into_iter().collect());
3382        let required = required.is_empty().not().then_some(required);
3383        let subtype = Some(UncheckedDataSchemaSubtype::Object(UncheckedObjectSchema {
3384            properties,
3385            required,
3386            other: other_object_schema,
3387        }));
3388
3389        PartialDataSchema {
3390            constant: None,
3391            default,
3392            unit,
3393            one_of: None,
3394            enumeration: None,
3395            read_only,
3396            write_only,
3397            format,
3398            subtype,
3399            other: other_data_schema,
3400        }
3401    }
3402}
3403
3404impl<T, DS, AS, OS> From<StringDataSchemaBuilder<T>> for UncheckedDataSchema<DS, AS, OS>
3405where
3406    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3407{
3408    fn from(builder: StringDataSchemaBuilder<T>) -> Self {
3409        let StringDataSchemaBuilder {
3410            inner,
3411            min_length,
3412            max_length,
3413            pattern,
3414            content_encoding,
3415            content_media_type,
3416        } = builder;
3417
3418        let DataSchemaBuilder {
3419            partial:
3420                PartialDataSchemaBuilder {
3421                    constant: _,
3422                    default,
3423                    unit,
3424                    one_of: _,
3425                    enumeration: _,
3426                    read_only,
3427                    write_only,
3428                    format,
3429                    other,
3430                    _marker: _,
3431                },
3432            info:
3433                HumanReadableInfo {
3434                    attype,
3435                    title,
3436                    titles,
3437                    description,
3438                    descriptions,
3439                },
3440        } = inner.into();
3441
3442        let subtype = Some(UncheckedDataSchemaSubtype::String(StringSchema {
3443            min_length,
3444            max_length,
3445            pattern,
3446            content_encoding,
3447            content_media_type,
3448        }));
3449
3450        UncheckedDataSchema {
3451            attype,
3452            title,
3453            titles,
3454            description,
3455            descriptions,
3456            constant: None,
3457            default,
3458            unit,
3459            one_of: None,
3460            enumeration: None,
3461            read_only,
3462            write_only,
3463            format,
3464            subtype,
3465            other,
3466        }
3467    }
3468}
3469
3470impl<T, DS, AS, OS> TryFrom<StringDataSchemaBuilder<T>> for DataSchema<DS, AS, OS>
3471where
3472    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3473{
3474    type Error = Error;
3475
3476    fn try_from(value: StringDataSchemaBuilder<T>) -> Result<Self, Self::Error> {
3477        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3478        data_schema.try_into()
3479    }
3480}
3481
3482impl<T, DS, AS, OS> From<StringDataSchemaBuilder<T>> for PartialDataSchema<DS, AS, OS>
3483where
3484    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
3485{
3486    fn from(builder: StringDataSchemaBuilder<T>) -> Self {
3487        let StringDataSchemaBuilder {
3488            inner,
3489            min_length,
3490            max_length,
3491            pattern,
3492            content_encoding,
3493            content_media_type,
3494        } = builder;
3495
3496        let PartialDataSchemaBuilder {
3497            constant: _,
3498            default,
3499            unit,
3500            one_of: _,
3501            enumeration: _,
3502            read_only,
3503            write_only,
3504            format,
3505            other,
3506            _marker: _,
3507        } = inner.into();
3508
3509        let subtype = Some(UncheckedDataSchemaSubtype::String(StringSchema {
3510            min_length,
3511            max_length,
3512            pattern,
3513            content_encoding,
3514            content_media_type,
3515        }));
3516
3517        PartialDataSchema {
3518            constant: None,
3519            default,
3520            unit,
3521            one_of: None,
3522            enumeration: None,
3523            read_only,
3524            write_only,
3525            format,
3526            subtype,
3527            other,
3528        }
3529    }
3530}
3531
3532impl<T, DS, AS, OS> From<ReadOnly<T>> for UncheckedDataSchema<DS, AS, OS>
3533where
3534    T: Into<UncheckedDataSchema<DS, AS, OS>>,
3535{
3536    fn from(builder: ReadOnly<T>) -> Self {
3537        let data_schema = builder.inner.into();
3538        Self {
3539            read_only: true,
3540            ..data_schema
3541        }
3542    }
3543}
3544
3545impl<T, DS, AS, OS> TryFrom<ReadOnly<T>> for DataSchema<DS, AS, OS>
3546where
3547    T: Into<UncheckedDataSchema<DS, AS, OS>>,
3548{
3549    type Error = Error;
3550
3551    fn try_from(value: ReadOnly<T>) -> Result<Self, Self::Error> {
3552        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3553        data_schema.try_into()
3554    }
3555}
3556
3557impl<T, DS, AS, OS> From<WriteOnly<T>> for UncheckedDataSchema<DS, AS, OS>
3558where
3559    T: Into<UncheckedDataSchema<DS, AS, OS>>,
3560{
3561    fn from(builder: WriteOnly<T>) -> Self {
3562        let data_schema = builder.inner.into();
3563        Self {
3564            read_only: false,
3565            ..data_schema
3566        }
3567    }
3568}
3569
3570impl<T, DS, AS, OS> TryFrom<WriteOnly<T>> for DataSchema<DS, AS, OS>
3571where
3572    T: Into<UncheckedDataSchema<DS, AS, OS>>,
3573{
3574    type Error = Error;
3575
3576    fn try_from(value: WriteOnly<T>) -> Result<Self, Self::Error> {
3577        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3578        data_schema.try_into()
3579    }
3580}
3581
3582impl<T, DS, AS, OS> From<ReadOnly<T>> for PartialDataSchema<DS, AS, OS>
3583where
3584    T: Into<PartialDataSchema<DS, AS, OS>>,
3585{
3586    fn from(builder: ReadOnly<T>) -> Self {
3587        let data_schema = builder.inner.into();
3588        Self {
3589            read_only: true,
3590            ..data_schema
3591        }
3592    }
3593}
3594
3595impl<T, DS, AS, OS> From<WriteOnly<T>> for PartialDataSchema<DS, AS, OS>
3596where
3597    T: Into<PartialDataSchema<DS, AS, OS>>,
3598{
3599    fn from(builder: WriteOnly<T>) -> Self {
3600        let data_schema = builder.inner.into();
3601        Self {
3602            read_only: false,
3603            ..data_schema
3604        }
3605    }
3606}
3607
3608impl<T, DS, AS, OS> From<EnumDataSchemaBuilder<T>> for UncheckedDataSchema<DS, AS, OS>
3609where
3610    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3611{
3612    fn from(builder: EnumDataSchemaBuilder<T>) -> Self {
3613        let DataSchemaBuilder {
3614            partial:
3615                PartialDataSchemaBuilder {
3616                    constant: _,
3617                    default,
3618                    unit,
3619                    one_of: _,
3620                    enumeration,
3621                    read_only,
3622                    write_only,
3623                    format,
3624                    other,
3625                    _marker: _,
3626                },
3627            info:
3628                HumanReadableInfo {
3629                    attype,
3630                    title,
3631                    titles,
3632                    description,
3633                    descriptions,
3634                },
3635        } = builder.inner.into();
3636
3637        let enumeration = Some(enumeration);
3638        Self {
3639            attype,
3640            title,
3641            titles,
3642            description,
3643            descriptions,
3644            constant: None,
3645            default,
3646            unit,
3647            one_of: None,
3648            enumeration,
3649            read_only,
3650            write_only,
3651            format,
3652            subtype: None,
3653            other,
3654        }
3655    }
3656}
3657
3658impl<T, DS, AS, OS> TryFrom<EnumDataSchemaBuilder<T>> for DataSchema<DS, AS, OS>
3659where
3660    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3661{
3662    type Error = Error;
3663
3664    fn try_from(value: EnumDataSchemaBuilder<T>) -> Result<Self, Self::Error> {
3665        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3666        data_schema.try_into()
3667    }
3668}
3669
3670impl<T, DS, AS, OS> From<EnumDataSchemaBuilder<T>> for PartialDataSchema<DS, AS, OS>
3671where
3672    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
3673{
3674    fn from(builder: EnumDataSchemaBuilder<T>) -> Self {
3675        let PartialDataSchemaBuilder {
3676            constant: _,
3677            default,
3678            unit,
3679            one_of: _,
3680            enumeration,
3681            read_only,
3682            write_only,
3683            format,
3684            other,
3685            _marker: _,
3686        } = builder.inner.into();
3687
3688        let enumeration = Some(enumeration);
3689        Self {
3690            constant: None,
3691            default,
3692            unit,
3693            one_of: None,
3694            enumeration,
3695            read_only,
3696            write_only,
3697            format,
3698            subtype: None,
3699            other,
3700        }
3701    }
3702}
3703
3704impl<T, DS, AS, OS> From<OneOfDataSchemaBuilder<T>> for UncheckedDataSchema<DS, AS, OS>
3705where
3706    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3707{
3708    fn from(builder: OneOfDataSchemaBuilder<T>) -> Self {
3709        let DataSchemaBuilder {
3710            partial:
3711                PartialDataSchemaBuilder {
3712                    constant: _,
3713                    default,
3714                    unit,
3715                    one_of,
3716                    enumeration: _,
3717                    read_only,
3718                    write_only,
3719                    format,
3720                    other,
3721                    _marker: _,
3722                },
3723            info:
3724                HumanReadableInfo {
3725                    attype,
3726                    title,
3727                    titles,
3728                    description,
3729                    descriptions,
3730                },
3731        } = builder.inner.into();
3732
3733        let one_of = Some(one_of);
3734        Self {
3735            attype,
3736            title,
3737            titles,
3738            description,
3739            descriptions,
3740            constant: None,
3741            default,
3742            unit,
3743            one_of,
3744            enumeration: None,
3745            read_only,
3746            write_only,
3747            format,
3748            subtype: None,
3749            other,
3750        }
3751    }
3752}
3753
3754impl<T, DS, AS, OS> TryFrom<OneOfDataSchemaBuilder<T>> for DataSchema<DS, AS, OS>
3755where
3756    T: Into<DataSchemaBuilder<DS, AS, OS, Extended>>,
3757{
3758    type Error = Error;
3759
3760    fn try_from(value: OneOfDataSchemaBuilder<T>) -> Result<Self, Self::Error> {
3761        let data_schema: UncheckedDataSchema<_, _, _> = value.into();
3762        data_schema.try_into()
3763    }
3764}
3765
3766impl<T, DS, AS, OS> From<OneOfDataSchemaBuilder<T>> for PartialDataSchema<DS, AS, OS>
3767where
3768    T: Into<PartialDataSchemaBuilder<DS, AS, OS, Extended>>,
3769{
3770    fn from(builder: OneOfDataSchemaBuilder<T>) -> Self {
3771        let PartialDataSchemaBuilder {
3772            constant: _,
3773            default,
3774            unit,
3775            one_of,
3776            enumeration: _,
3777            read_only,
3778            write_only,
3779            format,
3780            other,
3781            _marker: _,
3782        } = builder.inner.into();
3783
3784        let one_of = Some(one_of);
3785        Self {
3786            constant: None,
3787            default,
3788            unit,
3789            one_of,
3790            enumeration: None,
3791            read_only,
3792            write_only,
3793            format,
3794            subtype: None,
3795            other,
3796        }
3797    }
3798}
3799
3800pub(super) trait CheckableDataSchema {
3801    fn check(&self) -> Result<(), Error>;
3802}
3803
3804impl<DS, AS, OS> CheckableDataSchema for UncheckedDataSchema<DS, AS, OS> {
3805    fn check(&self) -> Result<(), Error> {
3806        check_data_schema_subtype(&self.subtype)?;
3807        check_one_of_schema(self.one_of.as_deref())?;
3808        Ok(())
3809    }
3810}
3811
3812impl<DS, AS, OS> CheckableDataSchema for PartialDataSchema<DS, AS, OS> {
3813    fn check(&self) -> Result<(), Error> {
3814        check_data_schema_subtype(&self.subtype)?;
3815        check_one_of_schema(self.one_of.as_deref())?;
3816        Ok(())
3817    }
3818}
3819
3820pub(super) fn check_data_schema_subtype<DS, AS, OS>(
3821    mut subtype: &Option<UncheckedDataSchemaSubtype<DS, AS, OS>>,
3822) -> Result<(), Error> {
3823    use UncheckedDataSchemaSubtype::*;
3824
3825    let mut stack = Vec::new();
3826
3827    loop {
3828        if let Some(subtype) = subtype.as_ref() {
3829            match subtype {
3830                Array(array) => {
3831                    match (array.min_items, array.max_items) {
3832                        (Some(min), Some(max))
3833                            if matches!(min.partial_cmp(&max), None | Some(Ordering::Greater)) =>
3834                        {
3835                            return Err(Error::InvalidMinMax)
3836                        }
3837                        _ => {}
3838                    };
3839
3840                    if let Some(items) = &array.items {
3841                        match items {
3842                            BoxedElemOrVec::Elem(item) => stack.push(item.as_ref()),
3843                            BoxedElemOrVec::Vec(items) => stack.extend(items.iter()),
3844                        }
3845                    }
3846                }
3847                Number(number) => {
3848                    match (number.minimum, number.maximum) {
3849                        (Some(x), _) if x.is_nan() => return Err(Error::NanMinMax),
3850                        (_, Some(x)) if x.is_nan() => return Err(Error::NanMinMax),
3851                        (Some(min), Some(max))
3852                            if matches!(min.partial_cmp(&max), None | Some(Ordering::Greater)) =>
3853                        {
3854                            return Err(Error::InvalidMinMax)
3855                        }
3856                        _ => {}
3857                    }
3858
3859                    match number.multiple_of {
3860                        Some(multiple_of) if multiple_of <= 0. => {
3861                            return Err(Error::InvalidMultipleOf)
3862                        }
3863                        _ => {}
3864                    }
3865                }
3866                Integer(integer) => match (integer.minimum, integer.maximum) {
3867                    (Some(min), Some(max))
3868                        if matches!(min.partial_cmp(&max), None | Some(Ordering::Greater)) =>
3869                    {
3870                        return Err(Error::InvalidMinMax)
3871                    }
3872                    _ => {}
3873                },
3874                Object(UncheckedObjectSchema {
3875                    properties: Some(properties),
3876                    ..
3877                }) => stack.extend(properties.values()),
3878                Object(_) | String(_) | Boolean | Null => {}
3879            }
3880        }
3881
3882        match stack.pop() {
3883            Some(new_data_schema) => {
3884                if let Some(children) = new_data_schema.one_of.as_deref() {
3885                    stack.extend(children.iter());
3886                }
3887
3888                subtype = &new_data_schema.subtype
3889            }
3890            None => break Ok(()),
3891        }
3892    }
3893}
3894
3895fn check_one_of_schema<T>(one_of: Option<&[T]>) -> Result<(), Error>
3896where
3897    T: CheckableDataSchema,
3898{
3899    one_of
3900        .map(|one_of| one_of.iter().try_for_each(|schema| schema.check()))
3901        .unwrap_or(Ok(()))
3902}
3903
3904impl<DS, AS, OS> TryFrom<UncheckedDataSchema<DS, AS, OS>> for DataSchema<DS, AS, OS> {
3905    type Error = Error;
3906
3907    fn try_from(data_schema: UncheckedDataSchema<DS, AS, OS>) -> Result<Self, Self::Error> {
3908        let UncheckedDataSchema {
3909            attype,
3910            title,
3911            titles,
3912            description,
3913            descriptions,
3914            constant,
3915            default,
3916            unit,
3917            one_of,
3918            enumeration,
3919            read_only,
3920            write_only,
3921            format,
3922            subtype,
3923            other,
3924        } = data_schema;
3925
3926        let titles = titles.map(|titles| titles.build()).transpose()?;
3927        let descriptions = descriptions
3928            .map(|descriptions| descriptions.build())
3929            .transpose()?;
3930        let one_of = one_of
3931            .map(|one_of| {
3932                one_of
3933                    .into_iter()
3934                    .map(|data_schema| data_schema.try_into())
3935                    .collect()
3936            })
3937            .transpose()?;
3938        let subtype = subtype.map(|subtype| subtype.try_into()).transpose()?;
3939
3940        Ok(Self {
3941            attype,
3942            title,
3943            titles,
3944            description,
3945            descriptions,
3946            constant,
3947            default,
3948            unit,
3949            one_of,
3950            enumeration,
3951            read_only,
3952            write_only,
3953            format,
3954            subtype,
3955            other,
3956        })
3957    }
3958}
3959
3960pub(crate) fn uri_variables_contains_arrays_objects<Other>(
3961    uri_variables: &UncheckedDataSchemaMap<Other>,
3962) -> bool
3963where
3964    Other: ExtendableThing,
3965{
3966    uri_variables.values().any(|schema| {
3967        matches!(
3968            &schema.subtype,
3969            Some(UncheckedDataSchemaSubtype::Object(_) | UncheckedDataSchemaSubtype::Array(_))
3970        )
3971    })
3972}
3973
3974impl<DS, AS, OS> TryFrom<UncheckedDataSchemaSubtype<DS, AS, OS>> for DataSchemaSubtype<DS, AS, OS> {
3975    type Error = Error;
3976
3977    fn try_from(value: UncheckedDataSchemaSubtype<DS, AS, OS>) -> Result<Self, Self::Error> {
3978        use UncheckedDataSchemaSubtype::*;
3979
3980        let out = match value {
3981            Array(array) => DataSchemaSubtype::Array(array.try_into()?),
3982            Boolean => DataSchemaSubtype::Boolean,
3983            Number(number) => DataSchemaSubtype::Number(number),
3984            Integer(integer) => DataSchemaSubtype::Integer(integer),
3985            Object(object) => DataSchemaSubtype::Object(object.try_into()?),
3986            String(string) => DataSchemaSubtype::String(string),
3987            Null => DataSchemaSubtype::Null,
3988        };
3989
3990        Ok(out)
3991    }
3992}
3993
3994impl<DS, AS, OS> TryFrom<UncheckedArraySchema<DS, AS, OS>> for ArraySchema<DS, AS, OS> {
3995    type Error = Error;
3996
3997    fn try_from(value: UncheckedArraySchema<DS, AS, OS>) -> Result<Self, Self::Error> {
3998        let UncheckedArraySchema {
3999            items,
4000            min_items,
4001            max_items,
4002            other,
4003        } = value;
4004        let items = items
4005            .map(|items| match items {
4006                BoxedElemOrVec::Elem(item) => (*item)
4007                    .try_into()
4008                    .map(|item| BoxedElemOrVec::Elem(Box::new(item))),
4009                BoxedElemOrVec::Vec(items) => items
4010                    .into_iter()
4011                    .map(TryInto::try_into)
4012                    .collect::<Result<_, _>>()
4013                    .map(BoxedElemOrVec::Vec),
4014            })
4015            .transpose()?;
4016
4017        Ok(Self {
4018            items,
4019            min_items,
4020            max_items,
4021            other,
4022        })
4023    }
4024}
4025
4026impl<DS, AS, OS> TryFrom<UncheckedObjectSchema<DS, AS, OS>> for ObjectSchema<DS, AS, OS> {
4027    type Error = Error;
4028
4029    fn try_from(value: UncheckedObjectSchema<DS, AS, OS>) -> Result<Self, Self::Error> {
4030        let UncheckedObjectSchema {
4031            properties,
4032            required,
4033            other,
4034        } = value;
4035        let properties = properties
4036            .map(|properties| {
4037                properties
4038                    .into_iter()
4039                    .map(|(k, v)| v.try_into().map(|v| (k, v)))
4040                    .collect()
4041            })
4042            .transpose()?;
4043
4044        Ok(Self {
4045            properties,
4046            required,
4047            other,
4048        })
4049    }
4050}
4051
4052#[cfg(test)]
4053mod tests {
4054    use alloc::{boxed::Box, string::*, vec};
4055    use serde::{Deserialize, Serialize};
4056    use serde_json::json;
4057
4058    use crate::{
4059        extend::ExtendableThing,
4060        hlist::{Cons, Nil},
4061        thing::{ArraySchema, BoxedElemOrVec, DataSchemaFromOther, ObjectSchema},
4062    };
4063
4064    use super::*;
4065
4066    #[test]
4067    fn null_simple() {
4068        let data_schema: DataSchemaFromOther<Nil> =
4069            DataSchemaBuilder::default().null().try_into().unwrap();
4070        assert_eq!(
4071            data_schema,
4072            DataSchema {
4073                attype: None,
4074                title: None,
4075                titles: None,
4076                description: None,
4077                descriptions: None,
4078                constant: None,
4079                default: None,
4080                unit: None,
4081                one_of: None,
4082                enumeration: None,
4083                read_only: false,
4084                write_only: false,
4085                format: None,
4086                subtype: Some(DataSchemaSubtype::Null),
4087                other: Nil,
4088            }
4089        );
4090    }
4091
4092    #[test]
4093    fn null_partial() {
4094        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4095            PartialDataSchemaBuilder::default().null().into();
4096        assert_eq!(
4097            data_schema,
4098            PartialDataSchema {
4099                constant: None,
4100                default: None,
4101                unit: None,
4102                one_of: None,
4103                enumeration: None,
4104                read_only: false,
4105                write_only: false,
4106                format: None,
4107                subtype: Some(UncheckedDataSchemaSubtype::Null),
4108                other: Nil,
4109            }
4110        );
4111    }
4112
4113    #[test]
4114    fn boolean_simple() {
4115        let data_schema: DataSchemaFromOther<Nil> =
4116            DataSchemaBuilder::default().bool().try_into().unwrap();
4117        assert_eq!(
4118            data_schema,
4119            DataSchema {
4120                attype: None,
4121                title: None,
4122                titles: None,
4123                description: None,
4124                descriptions: None,
4125                constant: None,
4126                default: None,
4127                unit: None,
4128                one_of: None,
4129                enumeration: None,
4130                read_only: false,
4131                write_only: false,
4132                format: None,
4133                subtype: Some(DataSchemaSubtype::Boolean),
4134                other: Nil,
4135            }
4136        );
4137    }
4138
4139    #[test]
4140    fn boolean_partial() {
4141        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4142            PartialDataSchemaBuilder::default().bool().into();
4143        assert_eq!(
4144            data_schema,
4145            PartialDataSchema {
4146                constant: None,
4147                default: None,
4148                unit: None,
4149                one_of: None,
4150                enumeration: None,
4151                read_only: false,
4152                write_only: false,
4153                format: None,
4154                subtype: Some(UncheckedDataSchemaSubtype::Boolean),
4155                other: Nil,
4156            }
4157        );
4158    }
4159
4160    #[test]
4161    fn string_simple() {
4162        let data_schema: DataSchemaFromOther<Nil> =
4163            DataSchemaBuilder::default().string().try_into().unwrap();
4164        assert_eq!(
4165            data_schema,
4166            DataSchema {
4167                attype: None,
4168                title: None,
4169                titles: None,
4170                description: None,
4171                descriptions: None,
4172                constant: None,
4173                default: None,
4174                unit: None,
4175                one_of: None,
4176                enumeration: None,
4177                read_only: false,
4178                write_only: false,
4179                format: None,
4180                subtype: Some(DataSchemaSubtype::String(StringSchema {
4181                    max_length: None,
4182                    min_length: None,
4183                    pattern: None,
4184                    content_encoding: None,
4185                    content_media_type: None,
4186                })),
4187                other: Nil,
4188            }
4189        );
4190    }
4191
4192    #[test]
4193    fn string_partial() {
4194        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4195            PartialDataSchemaBuilder::default().string().into();
4196        assert_eq!(
4197            data_schema,
4198            PartialDataSchema {
4199                constant: None,
4200                default: None,
4201                unit: None,
4202                one_of: None,
4203                enumeration: None,
4204                read_only: false,
4205                write_only: false,
4206                format: None,
4207                subtype: Some(UncheckedDataSchemaSubtype::String(StringSchema {
4208                    min_length: None,
4209                    max_length: None,
4210                    pattern: None,
4211                    content_encoding: None,
4212                    content_media_type: None,
4213                })),
4214                other: Nil,
4215            }
4216        );
4217    }
4218
4219    #[test]
4220    fn empty_simple_vec() {
4221        let data_schema: DataSchemaFromOther<Nil> =
4222            DataSchemaBuilder::default().vec().try_into().unwrap();
4223        assert_eq!(
4224            data_schema,
4225            DataSchema {
4226                attype: None,
4227                title: None,
4228                titles: None,
4229                description: None,
4230                descriptions: None,
4231                constant: None,
4232                default: None,
4233                unit: None,
4234                one_of: None,
4235                enumeration: None,
4236                read_only: false,
4237                write_only: false,
4238                format: None,
4239                subtype: Some(DataSchemaSubtype::Array(ArraySchema {
4240                    items: None,
4241                    min_items: None,
4242                    max_items: None,
4243                    other: Nil,
4244                })),
4245                other: Nil,
4246            }
4247        );
4248    }
4249
4250    #[test]
4251    fn empty_partial_vec() {
4252        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4253            PartialDataSchemaBuilder::default().vec().into();
4254        assert_eq!(
4255            data_schema,
4256            PartialDataSchema {
4257                constant: None,
4258                default: None,
4259                unit: None,
4260                one_of: None,
4261                enumeration: None,
4262                read_only: false,
4263                write_only: false,
4264                format: None,
4265                subtype: Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
4266                    items: None,
4267                    min_items: None,
4268                    max_items: None,
4269                    other: Nil,
4270                })),
4271                other: Nil,
4272            }
4273        );
4274    }
4275
4276    #[test]
4277    fn empty_simple_tuple() {
4278        let data_schema: DataSchemaFromOther<Nil> =
4279            DataSchemaBuilder::default().tuple().try_into().unwrap();
4280        assert_eq!(
4281            data_schema,
4282            DataSchema {
4283                attype: None,
4284                title: None,
4285                titles: None,
4286                description: None,
4287                descriptions: None,
4288                constant: None,
4289                default: None,
4290                unit: None,
4291                one_of: None,
4292                enumeration: None,
4293                read_only: false,
4294                write_only: false,
4295                format: None,
4296                subtype: Some(DataSchemaSubtype::Array(ArraySchema {
4297                    items: Some(BoxedElemOrVec::Vec(vec![])),
4298                    min_items: None,
4299                    max_items: None,
4300                    other: Nil,
4301                })),
4302                other: Nil,
4303            }
4304        );
4305    }
4306
4307    #[test]
4308    fn empty_partial_tuple() {
4309        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4310            PartialDataSchemaBuilder::default().tuple().into();
4311        assert_eq!(
4312            data_schema,
4313            PartialDataSchema {
4314                constant: None,
4315                default: None,
4316                unit: None,
4317                one_of: None,
4318                enumeration: None,
4319                read_only: false,
4320                write_only: false,
4321                format: None,
4322                subtype: Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
4323                    items: Some(BoxedElemOrVec::Vec(vec![])),
4324                    min_items: None,
4325                    max_items: None,
4326                    other: Nil,
4327                })),
4328                other: Nil,
4329            }
4330        );
4331    }
4332
4333    #[test]
4334    fn number_simple() {
4335        let data_schema: DataSchemaFromOther<Nil> =
4336            DataSchemaBuilder::default().number().try_into().unwrap();
4337        assert_eq!(
4338            data_schema,
4339            DataSchema {
4340                attype: None,
4341                title: None,
4342                titles: None,
4343                description: None,
4344                descriptions: None,
4345                constant: None,
4346                default: None,
4347                unit: None,
4348                one_of: None,
4349                enumeration: None,
4350                read_only: false,
4351                write_only: false,
4352                format: None,
4353                subtype: Some(DataSchemaSubtype::Number(NumberSchema {
4354                    maximum: None,
4355                    minimum: None,
4356                    multiple_of: None,
4357                })),
4358                other: Nil,
4359            }
4360        );
4361    }
4362    #[test]
4363    fn number_partial() {
4364        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4365            PartialDataSchemaBuilder::default().number().into();
4366        assert_eq!(
4367            data_schema,
4368            PartialDataSchema {
4369                constant: None,
4370                default: None,
4371                unit: None,
4372                one_of: None,
4373                enumeration: None,
4374                read_only: false,
4375                write_only: false,
4376                format: None,
4377                subtype: Some(UncheckedDataSchemaSubtype::Number(NumberSchema {
4378                    maximum: None,
4379                    minimum: None,
4380                    multiple_of: None,
4381                })),
4382                other: Nil,
4383            }
4384        );
4385    }
4386
4387    #[test]
4388    fn integer_simple() {
4389        let data_schema: DataSchemaFromOther<Nil> =
4390            DataSchemaBuilder::default().integer().try_into().unwrap();
4391        assert_eq!(
4392            data_schema,
4393            DataSchema {
4394                attype: None,
4395                title: None,
4396                titles: None,
4397                description: None,
4398                descriptions: None,
4399                constant: None,
4400                default: None,
4401                unit: None,
4402                one_of: None,
4403                enumeration: None,
4404                read_only: false,
4405                write_only: false,
4406                format: None,
4407                subtype: Some(DataSchemaSubtype::Integer(IntegerSchema {
4408                    maximum: None,
4409                    minimum: None,
4410                    multiple_of: None,
4411                })),
4412                other: Nil,
4413            }
4414        );
4415    }
4416
4417    #[test]
4418    fn partial_simple() {
4419        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4420            PartialDataSchemaBuilder::default().integer().into();
4421        assert_eq!(
4422            data_schema,
4423            PartialDataSchema {
4424                constant: None,
4425                default: None,
4426                unit: None,
4427                one_of: None,
4428                enumeration: None,
4429                read_only: false,
4430                write_only: false,
4431                format: None,
4432                subtype: Some(UncheckedDataSchemaSubtype::Integer(IntegerSchema {
4433                    maximum: None,
4434                    minimum: None,
4435                    multiple_of: None,
4436                })),
4437                other: Nil,
4438            }
4439        );
4440    }
4441
4442    #[test]
4443    fn empty_simple_object() {
4444        let data_schema: DataSchemaFromOther<Nil> =
4445            DataSchemaBuilder::default().object().try_into().unwrap();
4446        assert_eq!(
4447            data_schema,
4448            DataSchema {
4449                attype: None,
4450                title: None,
4451                titles: None,
4452                description: None,
4453                descriptions: None,
4454                constant: None,
4455                default: None,
4456                unit: None,
4457                one_of: None,
4458                enumeration: None,
4459                read_only: false,
4460                write_only: false,
4461                format: None,
4462                subtype: Some(DataSchemaSubtype::Object(ObjectSchema {
4463                    properties: None,
4464                    required: None,
4465                    other: Nil,
4466                })),
4467                other: Nil,
4468            }
4469        );
4470    }
4471
4472    #[test]
4473    fn empty_partial_object() {
4474        let data_schema: PartialDataSchema<Nil, Nil, Nil> =
4475            PartialDataSchemaBuilder::default().object().into();
4476        assert_eq!(
4477            data_schema,
4478            PartialDataSchema {
4479                constant: None,
4480                default: None,
4481                unit: None,
4482                one_of: None,
4483                enumeration: None,
4484                read_only: false,
4485                write_only: false,
4486                format: None,
4487                subtype: Some(UncheckedDataSchemaSubtype::Object(UncheckedObjectSchema {
4488                    properties: None,
4489                    required: None,
4490                    other: Nil,
4491                })),
4492                other: Nil,
4493            }
4494        );
4495    }
4496
4497    #[test]
4498    fn constant_simple() {
4499        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4500            .constant(json!({ "hello": 42 }))
4501            .try_into()
4502            .unwrap();
4503        assert_eq!(
4504            data_schema,
4505            DataSchema {
4506                attype: None,
4507                title: None,
4508                titles: None,
4509                description: None,
4510                descriptions: None,
4511                constant: Some(json!({
4512                    "hello": 42,
4513                })),
4514                default: None,
4515                unit: None,
4516                one_of: None,
4517                enumeration: None,
4518                read_only: true,
4519                write_only: false,
4520                format: None,
4521                subtype: None,
4522                other: Nil,
4523            }
4524        );
4525    }
4526
4527    #[test]
4528    fn constant_partial() {
4529        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
4530            .constant(json!({ "hello": 42 }))
4531            .into();
4532        assert_eq!(
4533            data_schema,
4534            PartialDataSchema {
4535                constant: Some(json!({
4536                    "hello": 42,
4537                })),
4538                default: None,
4539                unit: None,
4540                one_of: None,
4541                enumeration: None,
4542                read_only: true,
4543                write_only: false,
4544                format: None,
4545                subtype: None,
4546                other: Nil,
4547            }
4548        );
4549    }
4550
4551    #[test]
4552    fn enum_simple() {
4553        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4554            .enumeration("hello")
4555            .enumeration("world")
4556            .enumeration(42)
4557            .try_into()
4558            .unwrap();
4559        assert_eq!(
4560            data_schema,
4561            DataSchema {
4562                attype: None,
4563                title: None,
4564                titles: None,
4565                description: None,
4566                descriptions: None,
4567                constant: None,
4568                default: None,
4569                unit: None,
4570                one_of: None,
4571                enumeration: Some(vec!["hello".into(), "world".into(), 42.into()]),
4572                read_only: false,
4573                write_only: false,
4574                format: None,
4575                subtype: None,
4576                other: Nil,
4577            }
4578        );
4579    }
4580
4581    #[test]
4582    fn enum_partial() {
4583        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
4584            .enumeration("hello")
4585            .enumeration("world")
4586            .enumeration(42)
4587            .into();
4588        assert_eq!(
4589            data_schema,
4590            PartialDataSchema {
4591                constant: None,
4592                default: None,
4593                unit: None,
4594                one_of: None,
4595                enumeration: Some(vec!["hello".into(), "world".into(), 42.into()]),
4596                read_only: false,
4597                write_only: false,
4598                format: None,
4599                subtype: None,
4600                other: Nil,
4601            }
4602        );
4603    }
4604
4605    #[test]
4606    fn read_only_simple() {
4607        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4608            .bool()
4609            .read_only()
4610            .try_into()
4611            .unwrap();
4612        assert_eq!(
4613            data_schema,
4614            DataSchema {
4615                attype: None,
4616                title: None,
4617                titles: None,
4618                description: None,
4619                descriptions: None,
4620                constant: None,
4621                default: None,
4622                unit: None,
4623                one_of: None,
4624                enumeration: None,
4625                read_only: true,
4626                write_only: false,
4627                format: None,
4628                subtype: Some(DataSchemaSubtype::Boolean),
4629                other: Nil,
4630            }
4631        );
4632    }
4633
4634    #[test]
4635    fn read_only_partial() {
4636        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
4637            .bool()
4638            .read_only()
4639            .into();
4640        assert_eq!(
4641            data_schema,
4642            PartialDataSchema {
4643                constant: None,
4644                default: None,
4645                unit: None,
4646                one_of: None,
4647                enumeration: None,
4648                read_only: true,
4649                write_only: false,
4650                format: None,
4651                subtype: Some(UncheckedDataSchemaSubtype::Boolean),
4652                other: Nil,
4653            }
4654        );
4655    }
4656
4657    #[test]
4658    fn read_only_to_builder() {
4659        let data_schema_builder: DataSchemaBuilder<Nil, Nil, Nil, Extended> = ReadOnly {
4660            inner: DataSchemaBuilder::default(),
4661        }
4662        .into();
4663        assert_eq!(
4664            data_schema_builder,
4665            DataSchemaBuilder {
4666                partial: PartialDataSchemaBuilder {
4667                    constant: None,
4668                    default: None,
4669                    unit: None,
4670                    one_of: vec![],
4671                    enumeration: vec![],
4672                    read_only: true,
4673                    write_only: false,
4674                    format: None,
4675                    other: Nil,
4676                    _marker: PhantomData,
4677                },
4678                info: Default::default(),
4679            }
4680        );
4681    }
4682
4683    #[test]
4684    fn read_only_to_partial_builder() {
4685        let data_schema_builder: PartialDataSchemaBuilder<Nil, Nil, Nil, Extended> = ReadOnly {
4686            inner: PartialDataSchemaBuilder::default(),
4687        }
4688        .into();
4689        assert_eq!(
4690            data_schema_builder,
4691            PartialDataSchemaBuilder {
4692                constant: None,
4693                default: None,
4694                unit: None,
4695                one_of: vec![],
4696                enumeration: vec![],
4697                read_only: true,
4698                write_only: false,
4699                format: None,
4700                other: Nil,
4701                _marker: PhantomData,
4702            },
4703        );
4704    }
4705
4706    #[test]
4707    fn write_only_simple() {
4708        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4709            .bool()
4710            .write_only()
4711            .try_into()
4712            .unwrap();
4713        assert_eq!(
4714            data_schema,
4715            DataSchema {
4716                attype: None,
4717                title: None,
4718                titles: None,
4719                description: None,
4720                descriptions: None,
4721                constant: None,
4722                default: None,
4723                unit: None,
4724                one_of: None,
4725                enumeration: None,
4726                read_only: false,
4727                write_only: true,
4728                format: None,
4729                subtype: Some(DataSchemaSubtype::Boolean),
4730                other: Nil,
4731            }
4732        );
4733    }
4734
4735    #[test]
4736    fn write_only_partial() {
4737        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
4738            .bool()
4739            .write_only()
4740            .into();
4741        assert_eq!(
4742            data_schema,
4743            PartialDataSchema {
4744                constant: None,
4745                default: None,
4746                unit: None,
4747                one_of: None,
4748                enumeration: None,
4749                read_only: false,
4750                write_only: true,
4751                format: None,
4752                subtype: Some(UncheckedDataSchemaSubtype::Boolean),
4753                other: Nil,
4754            }
4755        );
4756    }
4757
4758    #[test]
4759    fn write_only_to_builder() {
4760        let data_schema_builder: DataSchemaBuilder<Nil, Nil, Nil, Extended> = WriteOnly {
4761            inner: DataSchemaBuilder::default(),
4762        }
4763        .into();
4764        assert_eq!(
4765            data_schema_builder,
4766            DataSchemaBuilder {
4767                partial: PartialDataSchemaBuilder {
4768                    constant: None,
4769                    default: None,
4770                    unit: None,
4771                    one_of: vec![],
4772                    enumeration: vec![],
4773                    read_only: false,
4774                    write_only: true,
4775                    format: None,
4776                    other: Nil,
4777                    _marker: PhantomData,
4778                },
4779                info: Default::default(),
4780            }
4781        );
4782    }
4783
4784    #[test]
4785    fn write_only_to_partial_builder() {
4786        let data_schema_builder: PartialDataSchemaBuilder<Nil, Nil, Nil, Extended> = WriteOnly {
4787            inner: PartialDataSchemaBuilder::default(),
4788        }
4789        .into();
4790        assert_eq!(
4791            data_schema_builder,
4792            PartialDataSchemaBuilder {
4793                constant: None,
4794                default: None,
4795                unit: None,
4796                one_of: vec![],
4797                enumeration: vec![],
4798                read_only: false,
4799                write_only: true,
4800                format: None,
4801                other: Nil,
4802                _marker: PhantomData,
4803            },
4804        );
4805    }
4806
4807    #[test]
4808    fn null_full() {
4809        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4810            .null()
4811            .attype("attype1")
4812            .attype("attype2")
4813            .title("title")
4814            .titles(|b| b.add("en", "title_en").add("it", "title_it"))
4815            .description("description")
4816            .descriptions(|b| b.add("en", "description_en").add("it", "description_it"))
4817            .default_value(["hello", "world"].as_slice())
4818            .unit("cm")
4819            .format("format")
4820            .try_into()
4821            .unwrap();
4822        assert_eq!(
4823            data_schema,
4824            DataSchema {
4825                attype: Some(vec!["attype1".to_string(), "attype2".to_string()]),
4826                title: Some("title".to_string()),
4827                titles: Some(
4828                    [("en", "title_en"), ("it", "title_it")]
4829                        .into_iter()
4830                        .map(|(a, b)| (a.parse().unwrap(), b.to_string()))
4831                        .collect()
4832                ),
4833                description: Some("description".to_string()),
4834                descriptions: Some(
4835                    [("en", "description_en"), ("it", "description_it")]
4836                        .into_iter()
4837                        .map(|(a, b)| (a.parse().unwrap(), b.to_string()))
4838                        .collect()
4839                ),
4840                constant: None,
4841                default: Some(json! { ["hello", "world"]}),
4842                unit: Some("cm".to_string()),
4843                one_of: None,
4844                enumeration: None,
4845                read_only: false,
4846                write_only: false,
4847                format: Some("format".to_string()),
4848                subtype: Some(DataSchemaSubtype::Null),
4849                other: Nil,
4850            }
4851        );
4852    }
4853
4854    #[test]
4855    fn enum_full() {
4856        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4857            .enumeration("variant1")
4858            .enumeration("variant2")
4859            .enumeration(3u32)
4860            .attype("attype")
4861            .title("title")
4862            .titles(|b| b.add("en", "title_en").add("it", "title_it"))
4863            .description("description")
4864            .descriptions(|b| b.add("en", "description_en").add("it", "description_it"))
4865            .default_value(["hello", "world"].as_slice())
4866            .unit("cm")
4867            .format("format")
4868            .try_into()
4869            .unwrap();
4870        assert_eq!(
4871            data_schema,
4872            DataSchema {
4873                attype: Some(vec!["attype".to_string()]),
4874                title: Some("title".to_string()),
4875                titles: Some(
4876                    [("en", "title_en"), ("it", "title_it")]
4877                        .into_iter()
4878                        .map(|(a, b)| (a.parse().unwrap(), b.to_string()))
4879                        .collect()
4880                ),
4881                description: Some("description".to_string()),
4882                descriptions: Some(
4883                    [("en", "description_en"), ("it", "description_it")]
4884                        .into_iter()
4885                        .map(|(a, b)| (a.parse().unwrap(), b.to_string()))
4886                        .collect()
4887                ),
4888                constant: None,
4889                default: Some(json! { ["hello", "world"]}),
4890                unit: Some("cm".to_string()),
4891                one_of: None,
4892                enumeration: Some(vec!["variant1".into(), "variant2".into(), 3.into()]),
4893                read_only: false,
4894                write_only: false,
4895                format: Some("format".to_string()),
4896                subtype: None,
4897                other: Nil,
4898            }
4899        );
4900    }
4901
4902    #[test]
4903    fn read_only_enum() {
4904        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4905            .enumeration("hello")
4906            .enumeration("world")
4907            .title("title")
4908            .default_value(["hello", "world"].as_slice())
4909            .read_only()
4910            .enumeration(42)
4911            .description("description")
4912            .try_into()
4913            .unwrap();
4914        assert_eq!(
4915            data_schema,
4916            DataSchema {
4917                attype: None,
4918                title: Some("title".to_string()),
4919                titles: None,
4920                description: Some("description".to_string()),
4921                descriptions: None,
4922                constant: None,
4923                default: Some(json! { ["hello", "world"]}),
4924                unit: None,
4925                one_of: None,
4926                enumeration: Some(vec!["hello".into(), "world".into(), 42.into()]),
4927                read_only: true,
4928                write_only: false,
4929                format: None,
4930                subtype: None,
4931                other: Nil,
4932            }
4933        );
4934    }
4935
4936    #[test]
4937    fn tuple_with_content() {
4938        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
4939            .tuple()
4940            .append(|b| b.finish_extend().constant("hello"))
4941            .append(|b| b.finish_extend().bool())
4942            .try_into()
4943            .unwrap();
4944        assert_eq!(
4945            data_schema,
4946            DataSchema {
4947                attype: None,
4948                title: None,
4949                titles: None,
4950                description: None,
4951                descriptions: None,
4952                constant: None,
4953                default: None,
4954                unit: None,
4955                one_of: None,
4956                enumeration: None,
4957                read_only: false,
4958                write_only: false,
4959                format: None,
4960                subtype: Some(DataSchemaSubtype::Array(ArraySchema {
4961                    items: Some(BoxedElemOrVec::Vec(vec![
4962                        DataSchema {
4963                            attype: None,
4964                            title: None,
4965                            titles: None,
4966                            description: None,
4967                            descriptions: None,
4968                            constant: Some("hello".into()),
4969                            default: None,
4970                            unit: None,
4971                            one_of: None,
4972                            enumeration: None,
4973                            read_only: true,
4974                            write_only: false,
4975                            format: None,
4976                            subtype: None,
4977                            other: Nil,
4978                        },
4979                        DataSchema {
4980                            attype: None,
4981                            title: None,
4982                            titles: None,
4983                            description: None,
4984                            descriptions: None,
4985                            constant: None,
4986                            default: None,
4987                            unit: None,
4988                            one_of: None,
4989                            enumeration: None,
4990                            read_only: false,
4991                            write_only: false,
4992                            format: None,
4993                            subtype: Some(DataSchemaSubtype::Boolean),
4994                            other: Nil,
4995                        },
4996                    ])),
4997                    min_items: None,
4998                    max_items: None,
4999                    other: Nil,
5000                })),
5001                other: Nil,
5002            }
5003        );
5004    }
5005
5006    #[test]
5007    fn vec_with_content() {
5008        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5009            .vec()
5010            .min_items(0)
5011            .max_items(5)
5012            .set_item(|b| b.finish_extend().constant("hello"))
5013            .try_into()
5014            .unwrap();
5015        assert_eq!(
5016            data_schema,
5017            DataSchema {
5018                attype: None,
5019                title: None,
5020                titles: None,
5021                description: None,
5022                descriptions: None,
5023                constant: None,
5024                default: None,
5025                unit: None,
5026                one_of: None,
5027                enumeration: None,
5028                read_only: false,
5029                write_only: false,
5030                format: None,
5031                subtype: Some(DataSchemaSubtype::Array(ArraySchema {
5032                    items: Some(BoxedElemOrVec::Elem(Box::new(DataSchema {
5033                        attype: None,
5034                        title: None,
5035                        titles: None,
5036                        description: None,
5037                        descriptions: None,
5038                        constant: Some("hello".into()),
5039                        default: None,
5040                        unit: None,
5041                        one_of: None,
5042                        enumeration: None,
5043                        read_only: true,
5044                        write_only: false,
5045                        format: None,
5046                        subtype: None,
5047                        other: Nil,
5048                    },))),
5049                    min_items: Some(0),
5050                    max_items: Some(5),
5051                    other: Nil,
5052                })),
5053                other: Nil,
5054            }
5055        );
5056    }
5057
5058    #[test]
5059    fn tuple_partial_with_content() {
5060        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
5061            .tuple()
5062            .append(|b| b.finish_extend().constant("hello"))
5063            .append(|b| b.finish_extend().bool())
5064            .try_into()
5065            .unwrap();
5066        assert_eq!(
5067            data_schema,
5068            PartialDataSchema {
5069                constant: None,
5070                default: None,
5071                unit: None,
5072                one_of: None,
5073                enumeration: None,
5074                read_only: false,
5075                write_only: false,
5076                format: None,
5077                subtype: Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
5078                    items: Some(BoxedElemOrVec::Vec(vec![
5079                        UncheckedDataSchema {
5080                            attype: None,
5081                            title: None,
5082                            titles: None,
5083                            description: None,
5084                            descriptions: None,
5085                            constant: Some("hello".into()),
5086                            default: None,
5087                            unit: None,
5088                            one_of: None,
5089                            enumeration: None,
5090                            read_only: true,
5091                            write_only: false,
5092                            format: None,
5093                            subtype: None,
5094                            other: Nil,
5095                        },
5096                        UncheckedDataSchema {
5097                            attype: None,
5098                            title: None,
5099                            titles: None,
5100                            description: None,
5101                            descriptions: None,
5102                            constant: None,
5103                            default: None,
5104                            unit: None,
5105                            one_of: None,
5106                            enumeration: None,
5107                            read_only: false,
5108                            write_only: false,
5109                            format: None,
5110                            subtype: Some(UncheckedDataSchemaSubtype::Boolean),
5111                            other: Nil,
5112                        },
5113                    ])),
5114                    min_items: None,
5115                    max_items: None,
5116                    other: Nil,
5117                })),
5118                other: Nil,
5119            }
5120        );
5121    }
5122
5123    #[test]
5124    fn vec_partial_with_content() {
5125        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
5126            .vec()
5127            .min_items(0)
5128            .max_items(5)
5129            .set_item(|b| b.finish_extend().constant("hello"))
5130            .try_into()
5131            .unwrap();
5132        assert_eq!(
5133            data_schema,
5134            PartialDataSchema {
5135                constant: None,
5136                default: None,
5137                unit: None,
5138                one_of: None,
5139                enumeration: None,
5140                read_only: false,
5141                write_only: false,
5142                format: None,
5143                subtype: Some(UncheckedDataSchemaSubtype::Array(UncheckedArraySchema {
5144                    items: Some(BoxedElemOrVec::Elem(Box::new(UncheckedDataSchema {
5145                        attype: None,
5146                        title: None,
5147                        titles: None,
5148                        description: None,
5149                        descriptions: None,
5150                        constant: Some("hello".into()),
5151                        default: None,
5152                        unit: None,
5153                        one_of: None,
5154                        enumeration: None,
5155                        read_only: true,
5156                        write_only: false,
5157                        format: None,
5158                        subtype: None,
5159                        other: Nil,
5160                    },))),
5161                    min_items: Some(0),
5162                    max_items: Some(5),
5163                    other: Nil,
5164                })),
5165                other: Nil,
5166            }
5167        );
5168    }
5169
5170    #[test]
5171    fn object_with_content() {
5172        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5173            .object()
5174            .property("hello", false, |b| b.finish_extend().bool())
5175            .property("world", true, |b| b.title("title").finish_extend().number())
5176            .try_into()
5177            .unwrap();
5178        assert_eq!(
5179            data_schema,
5180            DataSchema {
5181                attype: None,
5182                title: None,
5183                titles: None,
5184                description: None,
5185                descriptions: None,
5186                constant: None,
5187                default: None,
5188                unit: None,
5189                one_of: None,
5190                enumeration: None,
5191                read_only: false,
5192                write_only: false,
5193                format: None,
5194                subtype: Some(DataSchemaSubtype::Object(ObjectSchema {
5195                    properties: Some(
5196                        [
5197                            (
5198                                "hello".to_string(),
5199                                DataSchema {
5200                                    attype: None,
5201                                    title: None,
5202                                    titles: None,
5203                                    description: None,
5204                                    descriptions: None,
5205                                    constant: None,
5206                                    default: None,
5207                                    unit: None,
5208                                    one_of: None,
5209                                    enumeration: None,
5210                                    read_only: false,
5211                                    write_only: false,
5212                                    format: None,
5213                                    subtype: Some(DataSchemaSubtype::Boolean),
5214                                    other: Nil,
5215                                }
5216                            ),
5217                            (
5218                                "world".to_string(),
5219                                DataSchema {
5220                                    attype: None,
5221                                    title: Some("title".to_string()),
5222                                    titles: None,
5223                                    description: None,
5224                                    descriptions: None,
5225                                    constant: None,
5226                                    default: None,
5227                                    unit: None,
5228                                    one_of: None,
5229                                    enumeration: None,
5230                                    read_only: false,
5231                                    write_only: false,
5232                                    format: None,
5233                                    subtype: Some(DataSchemaSubtype::Number(NumberSchema {
5234                                        maximum: None,
5235                                        minimum: None,
5236                                        multiple_of: None,
5237                                    })),
5238                                    other: Nil,
5239                                }
5240                            )
5241                        ]
5242                        .into_iter()
5243                        .collect()
5244                    ),
5245                    required: Some(vec!["world".to_string()]),
5246                    other: Nil,
5247                })),
5248                other: Nil,
5249            }
5250        );
5251    }
5252
5253    #[test]
5254    fn object_partial_with_content() {
5255        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
5256            .object()
5257            .property("hello", false, |b| b.finish_extend().bool())
5258            .property("world", true, |b| b.finish_extend().title("title").number())
5259            .try_into()
5260            .unwrap();
5261        assert_eq!(
5262            data_schema,
5263            PartialDataSchema {
5264                constant: None,
5265                default: None,
5266                unit: None,
5267                one_of: None,
5268                enumeration: None,
5269                read_only: false,
5270                write_only: false,
5271                format: None,
5272                subtype: Some(UncheckedDataSchemaSubtype::Object(UncheckedObjectSchema {
5273                    properties: Some(
5274                        [
5275                            (
5276                                "hello".to_string(),
5277                                UncheckedDataSchema {
5278                                    attype: None,
5279                                    title: None,
5280                                    titles: None,
5281                                    description: None,
5282                                    descriptions: None,
5283                                    constant: None,
5284                                    default: None,
5285                                    unit: None,
5286                                    one_of: None,
5287                                    enumeration: None,
5288                                    read_only: false,
5289                                    write_only: false,
5290                                    format: None,
5291                                    subtype: Some(UncheckedDataSchemaSubtype::Boolean),
5292                                    other: Nil,
5293                                }
5294                            ),
5295                            (
5296                                "world".to_string(),
5297                                UncheckedDataSchema {
5298                                    attype: None,
5299                                    title: Some("title".to_string()),
5300                                    titles: None,
5301                                    description: None,
5302                                    descriptions: None,
5303                                    constant: None,
5304                                    default: None,
5305                                    unit: None,
5306                                    one_of: None,
5307                                    enumeration: None,
5308                                    read_only: false,
5309                                    write_only: false,
5310                                    format: None,
5311                                    subtype: Some(UncheckedDataSchemaSubtype::Number(
5312                                        NumberSchema {
5313                                            maximum: None,
5314                                            minimum: None,
5315                                            multiple_of: None,
5316                                        }
5317                                    )),
5318                                    other: Nil,
5319                                }
5320                            )
5321                        ]
5322                        .into_iter()
5323                        .collect()
5324                    ),
5325                    required: Some(vec!["world".to_string()]),
5326                    other: Nil,
5327                })),
5328                other: Nil,
5329            }
5330        );
5331    }
5332
5333    #[test]
5334    fn integer_with_data() {
5335        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5336            .integer()
5337            .exclusive_minimum(10)
5338            .maximum(5)
5339            .multiple_of(NonZeroU64::new(2).unwrap())
5340            .try_into()
5341            .unwrap();
5342        assert_eq!(
5343            data_schema,
5344            DataSchema {
5345                attype: None,
5346                title: None,
5347                titles: None,
5348                description: None,
5349                descriptions: None,
5350                constant: None,
5351                default: None,
5352                unit: None,
5353                one_of: None,
5354                enumeration: None,
5355                read_only: false,
5356                write_only: false,
5357                format: None,
5358                subtype: Some(DataSchemaSubtype::Integer(IntegerSchema {
5359                    maximum: Some(Maximum::Inclusive(5)),
5360                    minimum: Some(Minimum::Exclusive(10)),
5361                    multiple_of: Some(NonZeroU64::new(2).unwrap()),
5362                })),
5363                other: Nil,
5364            },
5365        );
5366
5367        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5368            .integer()
5369            .minimum(10)
5370            .exclusive_maximum(5)
5371            .try_into()
5372            .unwrap();
5373        assert_eq!(
5374            data_schema,
5375            DataSchema {
5376                attype: None,
5377                title: None,
5378                titles: None,
5379                description: None,
5380                descriptions: None,
5381                constant: None,
5382                default: None,
5383                unit: None,
5384                one_of: None,
5385                enumeration: None,
5386                read_only: false,
5387                write_only: false,
5388                format: None,
5389                subtype: Some(DataSchemaSubtype::Integer(IntegerSchema {
5390                    maximum: Some(Maximum::Exclusive(5)),
5391                    minimum: Some(Minimum::Inclusive(10)),
5392                    multiple_of: None,
5393                })),
5394                other: Nil,
5395            },
5396        );
5397    }
5398
5399    #[test]
5400    fn number_with_data() {
5401        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5402            .number()
5403            .exclusive_minimum(10.)
5404            .maximum(5.)
5405            .multiple_of(2.)
5406            .try_into()
5407            .unwrap();
5408        assert_eq!(
5409            data_schema,
5410            DataSchema {
5411                attype: None,
5412                title: None,
5413                titles: None,
5414                description: None,
5415                descriptions: None,
5416                constant: None,
5417                default: None,
5418                unit: None,
5419                one_of: None,
5420                enumeration: None,
5421                read_only: false,
5422                write_only: false,
5423                format: None,
5424                subtype: Some(DataSchemaSubtype::Number(NumberSchema {
5425                    maximum: Some(Maximum::Inclusive(5.)),
5426                    minimum: Some(Minimum::Exclusive(10.)),
5427                    multiple_of: Some(2.),
5428                })),
5429                other: Nil,
5430            },
5431        );
5432
5433        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5434            .number()
5435            .minimum(10.)
5436            .exclusive_maximum(5.)
5437            .multiple_of(2.)
5438            .try_into()
5439            .unwrap();
5440        assert_eq!(
5441            data_schema,
5442            DataSchema {
5443                attype: None,
5444                title: None,
5445                titles: None,
5446                description: None,
5447                descriptions: None,
5448                constant: None,
5449                default: None,
5450                unit: None,
5451                one_of: None,
5452                enumeration: None,
5453                read_only: false,
5454                write_only: false,
5455                format: None,
5456                subtype: Some(DataSchemaSubtype::Number(NumberSchema {
5457                    maximum: Some(Maximum::Exclusive(5.)),
5458                    minimum: Some(Minimum::Inclusive(10.)),
5459                    multiple_of: Some(2.),
5460                })),
5461                other: Nil,
5462            },
5463        );
5464    }
5465
5466    #[test]
5467    fn string_with_data() {
5468        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5469            .string()
5470            .min_length(5)
5471            .max_length(32)
5472            .pattern("pattern")
5473            .content_encoding("content encoding")
5474            .content_media_type("content media type")
5475            .try_into()
5476            .unwrap();
5477        assert_eq!(
5478            data_schema,
5479            DataSchema {
5480                attype: None,
5481                title: None,
5482                titles: None,
5483                description: None,
5484                descriptions: None,
5485                constant: None,
5486                default: None,
5487                unit: None,
5488                one_of: None,
5489                enumeration: None,
5490                read_only: false,
5491                write_only: false,
5492                format: None,
5493                subtype: Some(DataSchemaSubtype::String(StringSchema {
5494                    min_length: Some(5),
5495                    max_length: Some(32),
5496                    pattern: Some("pattern".to_string()),
5497                    content_encoding: Some("content encoding".to_string()),
5498                    content_media_type: Some("content media type".to_string()),
5499                })),
5500                other: Nil,
5501            },
5502        );
5503    }
5504
5505    #[test]
5506    fn one_of_simple() {
5507        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5508            .one_of(|b| b.finish_extend().number())
5509            .one_of(|b| b.finish_extend().integer())
5510            .one_of(|b| b.finish_extend().string())
5511            .try_into()
5512            .unwrap();
5513        assert_eq!(
5514            data_schema,
5515            DataSchema {
5516                attype: None,
5517                title: None,
5518                titles: None,
5519                description: None,
5520                descriptions: None,
5521                constant: None,
5522                default: None,
5523                unit: None,
5524                one_of: Some(vec![
5525                    DataSchema {
5526                        attype: None,
5527                        title: None,
5528                        titles: None,
5529                        description: None,
5530                        descriptions: None,
5531                        constant: None,
5532                        default: None,
5533                        unit: None,
5534                        one_of: None,
5535                        enumeration: None,
5536                        read_only: false,
5537                        write_only: false,
5538                        format: None,
5539                        subtype: Some(DataSchemaSubtype::Number(NumberSchema {
5540                            maximum: None,
5541                            minimum: None,
5542                            multiple_of: None,
5543                        })),
5544                        other: Nil,
5545                    },
5546                    DataSchema {
5547                        attype: None,
5548                        title: None,
5549                        titles: None,
5550                        description: None,
5551                        descriptions: None,
5552                        constant: None,
5553                        default: None,
5554                        unit: None,
5555                        one_of: None,
5556                        enumeration: None,
5557                        read_only: false,
5558                        write_only: false,
5559                        format: None,
5560                        subtype: Some(DataSchemaSubtype::Integer(IntegerSchema {
5561                            maximum: None,
5562                            minimum: None,
5563                            multiple_of: None,
5564                        })),
5565                        other: Nil,
5566                    },
5567                    DataSchema {
5568                        attype: None,
5569                        title: None,
5570                        titles: None,
5571                        description: None,
5572                        descriptions: None,
5573                        constant: None,
5574                        default: None,
5575                        unit: None,
5576                        one_of: None,
5577                        enumeration: None,
5578                        read_only: false,
5579                        write_only: false,
5580                        format: None,
5581                        subtype: Some(DataSchemaSubtype::String(StringSchema {
5582                            min_length: None,
5583                            max_length: None,
5584                            pattern: None,
5585                            content_encoding: None,
5586                            content_media_type: None,
5587                        })),
5588                        other: Nil,
5589                    },
5590                ]),
5591                enumeration: None,
5592                read_only: false,
5593                write_only: false,
5594                format: None,
5595                subtype: None,
5596                other: Nil,
5597            },
5598        );
5599    }
5600
5601    #[test]
5602    fn one_of_nested() {
5603        let data_schema: DataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5604            .object()
5605            .property("hello", true, |b| {
5606                b.finish_extend()
5607                    .one_of(|b| b.finish_extend().string())
5608                    .one_of(|b| b.finish_extend().integer())
5609            })
5610            .try_into()
5611            .unwrap();
5612        assert_eq!(
5613            data_schema,
5614            DataSchema {
5615                attype: None,
5616                title: None,
5617                titles: None,
5618                description: None,
5619                descriptions: None,
5620                constant: None,
5621                default: None,
5622                unit: None,
5623                one_of: None,
5624                enumeration: None,
5625                read_only: false,
5626                write_only: false,
5627                format: None,
5628                subtype: Some(DataSchemaSubtype::Object(ObjectSchema {
5629                    properties: Some(
5630                        [(
5631                            "hello".to_string(),
5632                            DataSchema {
5633                                attype: None,
5634                                title: None,
5635                                titles: None,
5636                                description: None,
5637                                descriptions: None,
5638                                constant: None,
5639                                default: None,
5640                                unit: None,
5641                                one_of: Some(vec![
5642                                    DataSchema {
5643                                        attype: None,
5644                                        title: None,
5645                                        titles: None,
5646                                        description: None,
5647                                        descriptions: None,
5648                                        constant: None,
5649                                        default: None,
5650                                        unit: None,
5651                                        one_of: None,
5652                                        enumeration: None,
5653                                        read_only: false,
5654                                        write_only: false,
5655                                        format: None,
5656                                        subtype: Some(DataSchemaSubtype::String(StringSchema {
5657                                            min_length: None,
5658                                            max_length: None,
5659                                            pattern: None,
5660                                            content_encoding: None,
5661                                            content_media_type: None,
5662                                        })),
5663                                        other: Nil,
5664                                    },
5665                                    DataSchema {
5666                                        attype: None,
5667                                        title: None,
5668                                        titles: None,
5669                                        description: None,
5670                                        descriptions: None,
5671                                        constant: None,
5672                                        default: None,
5673                                        unit: None,
5674                                        one_of: None,
5675                                        enumeration: None,
5676                                        read_only: false,
5677                                        write_only: false,
5678                                        format: None,
5679                                        subtype: Some(DataSchemaSubtype::Integer(IntegerSchema {
5680                                            maximum: None,
5681                                            minimum: None,
5682                                            multiple_of: None,
5683                                        })),
5684                                        other: Nil,
5685                                    },
5686                                ]),
5687                                enumeration: None,
5688                                read_only: false,
5689                                write_only: false,
5690                                format: None,
5691                                subtype: None,
5692                                other: Nil,
5693                            }
5694                        ),]
5695                        .into_iter()
5696                        .collect()
5697                    ),
5698                    required: Some(vec!["hello".to_string()]),
5699                    other: Nil,
5700                })),
5701                other: Nil,
5702            },
5703        );
5704    }
5705
5706    #[test]
5707    fn check_valid_data_schema() {
5708        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5709            .one_of(|b| {
5710                b.finish_extend()
5711                    .vec()
5712                    .min_items(2)
5713                    .max_items(5)
5714                    .set_item(|b| {
5715                        b.finish_extend()
5716                            .one_of(|b| {
5717                                b.finish_extend()
5718                                    .number()
5719                                    .minimum(0.)
5720                                    .maximum(5.)
5721                                    .multiple_of(2.)
5722                            })
5723                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5724                    })
5725            })
5726            .one_of(|b| {
5727                b.finish_extend()
5728                    .number()
5729                    .minimum(20.)
5730                    .maximum(42.)
5731                    .multiple_of(7.)
5732            })
5733            .one_of(|b| {
5734                b.finish_extend().object().property("a", false, |b| {
5735                    b.finish_extend().integer().minimum(10).maximum(20)
5736                })
5737            })
5738            .into();
5739
5740        assert!(data_schema.check().is_ok());
5741    }
5742
5743    #[test]
5744    fn check_invalid_data_schema() {
5745        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5746            .one_of(|b| {
5747                b.finish_extend()
5748                    .vec()
5749                    .min_items(5)
5750                    .max_items(2)
5751                    .set_item(|b| {
5752                        b.finish_extend()
5753                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5754                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5755                    })
5756            })
5757            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(42.))
5758            .one_of(|b| {
5759                b.finish_extend().object().property("a", false, |b| {
5760                    b.finish_extend().integer().minimum(10).maximum(20)
5761                })
5762            })
5763            .into();
5764
5765        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5766
5767        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5768            .one_of(|b| {
5769                b.finish_extend()
5770                    .vec()
5771                    .min_items(2)
5772                    .max_items(5)
5773                    .set_item(|b| {
5774                        b.finish_extend()
5775                            .one_of(|b| b.finish_extend().number().minimum(5.).maximum(0.))
5776                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5777                    })
5778            })
5779            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(42.))
5780            .one_of(|b| {
5781                b.finish_extend().object().property("a", false, |b| {
5782                    b.finish_extend().integer().minimum(10).maximum(20)
5783                })
5784            })
5785            .into();
5786
5787        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5788
5789        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5790            .one_of(|b| {
5791                b.finish_extend()
5792                    .vec()
5793                    .min_items(2)
5794                    .max_items(5)
5795                    .set_item(|b| {
5796                        b.finish_extend()
5797                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5798                            .one_of(|b| b.finish_extend().integer().minimum(10).maximum(5))
5799                    })
5800            })
5801            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(42.))
5802            .one_of(|b| {
5803                b.finish_extend().object().property("a", false, |b| {
5804                    b.finish_extend().integer().minimum(10).maximum(20)
5805                })
5806            })
5807            .into();
5808
5809        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5810
5811        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5812            .one_of(|b| {
5813                b.finish_extend()
5814                    .vec()
5815                    .min_items(2)
5816                    .max_items(5)
5817                    .set_item(|b| {
5818                        b.finish_extend()
5819                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5820                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5821                    })
5822            })
5823            .one_of(|b| b.finish_extend().number().minimum(42.).maximum(20.))
5824            .one_of(|b| {
5825                b.finish_extend().object().property("a", false, |b| {
5826                    b.finish_extend().integer().minimum(10).maximum(20)
5827                })
5828            })
5829            .into();
5830
5831        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5832
5833        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5834            .one_of(|b| {
5835                b.finish_extend()
5836                    .vec()
5837                    .min_items(2)
5838                    .max_items(5)
5839                    .set_item(|b| {
5840                        b.finish_extend()
5841                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5842                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5843                    })
5844            })
5845            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(f64::NAN))
5846            .one_of(|b| {
5847                b.finish_extend().object().property("a", false, |b| {
5848                    b.finish_extend().integer().minimum(10).maximum(20)
5849                })
5850            })
5851            .into();
5852
5853        assert_eq!(data_schema.check().unwrap_err(), Error::NanMinMax);
5854
5855        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5856            .one_of(|b| {
5857                b.finish_extend()
5858                    .vec()
5859                    .min_items(2)
5860                    .max_items(5)
5861                    .set_item(|b| {
5862                        b.finish_extend()
5863                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5864                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5865                    })
5866            })
5867            .one_of(|b| b.finish_extend().number().minimum(f64::NAN).maximum(42.))
5868            .one_of(|b| {
5869                b.finish_extend().object().property("a", false, |b| {
5870                    b.finish_extend().integer().minimum(10).maximum(20)
5871                })
5872            })
5873            .into();
5874
5875        assert_eq!(data_schema.check().unwrap_err(), Error::NanMinMax);
5876
5877        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5878            .one_of(|b| {
5879                b.finish_extend()
5880                    .vec()
5881                    .min_items(2)
5882                    .max_items(5)
5883                    .set_item(|b| {
5884                        b.finish_extend()
5885                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5886                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5887                    })
5888            })
5889            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(42.))
5890            .one_of(|b| {
5891                b.finish_extend().object().property("a", false, |b| {
5892                    b.finish_extend().integer().minimum(20).maximum(10)
5893                })
5894            })
5895            .into();
5896
5897        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5898
5899        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5900            .one_of(|b| {
5901                b.finish_extend()
5902                    .vec()
5903                    .min_items(2)
5904                    .max_items(5)
5905                    .set_item(|b| {
5906                        b.finish_extend()
5907                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5908                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5909                    })
5910            })
5911            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(42.))
5912            .one_of(|b| {
5913                b.finish_extend()
5914                    .object()
5915                    .property("a", false, |b| {
5916                        b.finish_extend().integer().minimum(10).maximum(20)
5917                    })
5918                    .property("b", false, |b| {
5919                        b.finish_extend().integer().minimum(20).maximum(10)
5920                    })
5921            })
5922            .into();
5923
5924        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5925
5926        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5927            .one_of(|b| {
5928                b.finish_extend()
5929                    .vec()
5930                    .min_items(2)
5931                    .max_items(5)
5932                    .set_item(|b| {
5933                        b.finish_extend()
5934                            .one_of(|b| b.finish_extend().number().minimum(0.).maximum(5.))
5935                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5936                    })
5937            })
5938            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(42.))
5939            .one_of(|b| {
5940                b.finish_extend().object().property("a", false, |b| {
5941                    b.finish_extend().integer().minimum(10).maximum(20)
5942                })
5943            })
5944            .one_of(|b| {
5945                b.finish_extend()
5946                    .one_of(|b| b.finish_extend().number().minimum(20.).maximum(10.))
5947            })
5948            .into();
5949
5950        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5951
5952        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5953            .one_of(|b| {
5954                b.finish_extend()
5955                    .vec()
5956                    .min_items(2)
5957                    .max_items(5)
5958                    .set_item(|b| {
5959                        b.finish_extend()
5960                            .one_of(|b| {
5961                                b.finish_extend()
5962                                    .one_of(|b| b.finish_extend().number().minimum(5.).maximum(0.))
5963                            })
5964                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
5965                    })
5966            })
5967            .one_of(|b| b.finish_extend().number().minimum(20.).maximum(42.))
5968            .one_of(|b| {
5969                b.finish_extend().object().property("a", false, |b| {
5970                    b.finish_extend().integer().minimum(10).maximum(20)
5971                })
5972            })
5973            .into();
5974
5975        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5976    }
5977
5978    #[test]
5979    fn check_invalid_data_schema_with_complex_minmax() {
5980        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5981            .integer()
5982            .exclusive_minimum(2)
5983            .maximum(2)
5984            .into();
5985
5986        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5987
5988        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5989            .integer()
5990            .minimum(2)
5991            .exclusive_maximum(2)
5992            .into();
5993
5994        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
5995
5996        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
5997            .number()
5998            .exclusive_minimum(2.)
5999            .maximum(2.)
6000            .into();
6001
6002        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
6003
6004        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
6005            .number()
6006            .minimum(2.)
6007            .exclusive_maximum(2.)
6008            .into();
6009
6010        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMinMax);
6011    }
6012
6013    #[test]
6014    fn check_invalid_data_schema_multiple_of() {
6015        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
6016            .vec()
6017            .set_item(|b| b.finish_extend().number().multiple_of(0.))
6018            .into();
6019
6020        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMultipleOf);
6021
6022        let data_schema: UncheckedDataSchemaFromOther<Nil> = DataSchemaBuilder::default()
6023            .vec()
6024            .set_item(|b| b.finish_extend().number().multiple_of(-2.))
6025            .into();
6026
6027        assert_eq!(data_schema.check().unwrap_err(), Error::InvalidMultipleOf);
6028    }
6029
6030    #[test]
6031    fn check_valid_partial_data_schema() {
6032        let data_schema: PartialDataSchema<Nil, Nil, Nil> = PartialDataSchemaBuilder::default()
6033            .one_of(|b| {
6034                b.finish_extend()
6035                    .vec()
6036                    .min_items(2)
6037                    .max_items(5)
6038                    .set_item(|b| {
6039                        b.finish_extend()
6040                            .one_of(|b| {
6041                                b.finish_extend()
6042                                    .number()
6043                                    .minimum(0.)
6044                                    .maximum(5.)
6045                                    .multiple_of(2.)
6046                            })
6047                            .one_of(|b| b.finish_extend().integer().minimum(5).maximum(10))
6048                    })
6049            })
6050            .one_of(|b| {
6051                b.finish_extend()
6052                    .number()
6053                    .minimum(20.)
6054                    .maximum(42.)
6055                    .multiple_of(3.)
6056            })
6057            .one_of(|b| {
6058                b.finish_extend().object().property("a", false, |b| {
6059                    b.finish_extend().integer().minimum(10).maximum(20)
6060                })
6061            })
6062            .into();
6063
6064        assert!(data_schema.check().is_ok());
6065    }
6066
6067    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6068    struct A(i32);
6069    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6070    struct B(String);
6071
6072    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6073    struct ThingExtA {}
6074
6075    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6076    struct DataSchemaExtA {
6077        a: A,
6078    }
6079
6080    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6081    struct ArraySchemaExtA {
6082        b: A,
6083    }
6084
6085    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6086    struct ObjectSchemaExtA {
6087        c: A,
6088    }
6089
6090    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6091    struct ThingExtB {}
6092
6093    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6094    struct DataSchemaExtB {
6095        d: B,
6096    }
6097
6098    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6099    struct ArraySchemaExtB {
6100        e: B,
6101    }
6102
6103    #[derive(Debug, PartialEq, Serialize, Deserialize)]
6104    struct ObjectSchemaExtB {
6105        f: B,
6106    }
6107
6108    impl ExtendableThing for ThingExtA {
6109        type InteractionAffordance = ();
6110        type PropertyAffordance = ();
6111        type ActionAffordance = ();
6112        type EventAffordance = ();
6113        type Form = ();
6114        type ExpectedResponse = ();
6115        type DataSchema = DataSchemaExtA;
6116        type ObjectSchema = ObjectSchemaExtA;
6117        type ArraySchema = ArraySchemaExtA;
6118    }
6119
6120    impl ExtendableThing for ThingExtB {
6121        type InteractionAffordance = ();
6122        type PropertyAffordance = ();
6123        type ActionAffordance = ();
6124        type EventAffordance = ();
6125        type Form = ();
6126        type ExpectedResponse = ();
6127        type DataSchema = DataSchemaExtB;
6128        type ObjectSchema = ObjectSchemaExtB;
6129        type ArraySchema = ArraySchemaExtB;
6130    }
6131
6132    #[test]
6133    fn extend_data_schema() {
6134        let data_schema: DataSchemaFromOther<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
6135            DataSchemaBuilder::<Cons<ThingExtB, Cons<ThingExtA, Nil>>, _, _, _>::empty()
6136                .ext(DataSchemaExtA { a: A(1) })
6137                .ext_with(|| DataSchemaExtB {
6138                    d: B("hello".to_string()),
6139                })
6140                .finish_extend()
6141                .title("title")
6142                .null()
6143                .try_into()
6144                .unwrap();
6145
6146        assert_eq!(
6147            data_schema,
6148            DataSchema {
6149                title: Some("title".to_string()),
6150                other: Nil::cons(DataSchemaExtA { a: A(1) }).cons(DataSchemaExtB {
6151                    d: B("hello".to_string())
6152                }),
6153                attype: Default::default(),
6154                titles: Default::default(),
6155                description: Default::default(),
6156                descriptions: Default::default(),
6157                constant: Default::default(),
6158                default: Default::default(),
6159                unit: Default::default(),
6160                one_of: Default::default(),
6161                enumeration: Default::default(),
6162                read_only: Default::default(),
6163                write_only: Default::default(),
6164                format: Default::default(),
6165                subtype: Some(DataSchemaSubtype::Null),
6166            }
6167        );
6168    }
6169
6170    #[test]
6171    fn extend_data_schema_with_vec() {
6172        let data_schema: DataSchemaFromOther<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
6173            DataSchemaBuilder::<
6174                Cons<ThingExtB, Cons<ThingExtA, Nil>>,
6175                Cons<ArraySchemaExtB, Cons<ArraySchemaExtA, Nil>>,
6176                _,
6177                _,
6178            >::empty()
6179            .ext(DataSchemaExtA { a: A(1) })
6180            .ext_with(|| DataSchemaExtB {
6181                d: B("hello".to_string()),
6182            })
6183            .finish_extend()
6184            .title("title")
6185            .vec_ext(|b| {
6186                b.ext(ArraySchemaExtA { b: A(2) })
6187                    .ext_with(|| ArraySchemaExtB {
6188                        e: B("world".to_string()),
6189                    })
6190            })
6191            .max_items(10)
6192            .try_into()
6193            .unwrap();
6194
6195        assert_eq!(
6196            data_schema,
6197            DataSchema {
6198                title: Some("title".to_string()),
6199                other: Nil::cons(DataSchemaExtA { a: A(1) }).cons(DataSchemaExtB {
6200                    d: B("hello".to_string())
6201                }),
6202                attype: Default::default(),
6203                titles: Default::default(),
6204                description: Default::default(),
6205                descriptions: Default::default(),
6206                constant: Default::default(),
6207                default: Default::default(),
6208                unit: Default::default(),
6209                one_of: Default::default(),
6210                enumeration: Default::default(),
6211                read_only: Default::default(),
6212                write_only: Default::default(),
6213                format: Default::default(),
6214                subtype: Some(DataSchemaSubtype::Array(ArraySchema {
6215                    other: Nil::cons(ArraySchemaExtA { b: A(2) }).cons(ArraySchemaExtB {
6216                        e: B("world".to_string())
6217                    }),
6218                    max_items: Some(10),
6219                    items: Default::default(),
6220                    min_items: Default::default(),
6221                })),
6222            }
6223        );
6224    }
6225
6226    #[test]
6227    fn extend_data_schema_with_tuple() {
6228        let data_schema: DataSchemaFromOther<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
6229            DataSchemaBuilder::<
6230                Cons<ThingExtB, Cons<ThingExtA, Nil>>,
6231                Cons<ArraySchemaExtB, Cons<ArraySchemaExtA, Nil>>,
6232                _,
6233                _,
6234            >::empty()
6235            .ext(DataSchemaExtA { a: A(1) })
6236            .ext_with(|| DataSchemaExtB {
6237                d: B("hello".to_string()),
6238            })
6239            .finish_extend()
6240            .title("title")
6241            .tuple_ext(|b| {
6242                b.ext(ArraySchemaExtA { b: A(2) })
6243                    .ext_with(|| ArraySchemaExtB {
6244                        e: B("world".to_string()),
6245                    })
6246            })
6247            .try_into()
6248            .unwrap();
6249
6250        assert_eq!(
6251            data_schema,
6252            DataSchema {
6253                title: Some("title".to_string()),
6254                other: Nil::cons(DataSchemaExtA { a: A(1) }).cons(DataSchemaExtB {
6255                    d: B("hello".to_string())
6256                }),
6257                attype: Default::default(),
6258                titles: Default::default(),
6259                description: Default::default(),
6260                descriptions: Default::default(),
6261                constant: Default::default(),
6262                default: Default::default(),
6263                unit: Default::default(),
6264                one_of: Default::default(),
6265                enumeration: Default::default(),
6266                read_only: Default::default(),
6267                write_only: Default::default(),
6268                format: Default::default(),
6269                subtype: Some(DataSchemaSubtype::Array(ArraySchema {
6270                    other: Nil::cons(ArraySchemaExtA { b: A(2) }).cons(ArraySchemaExtB {
6271                        e: B("world".to_string())
6272                    }),
6273                    items: Some(BoxedElemOrVec::Vec(Vec::new())),
6274                    max_items: Default::default(),
6275                    min_items: Default::default(),
6276                })),
6277            }
6278        );
6279    }
6280
6281    #[test]
6282    fn extend_data_schema_with_object() {
6283        let data_schema: DataSchemaFromOther<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
6284            DataSchemaBuilder::<
6285                Cons<ThingExtB, Cons<ThingExtA, Nil>>,
6286                _,
6287                Cons<ObjectSchemaExtB, Cons<ObjectSchemaExtA, Nil>>,
6288                _,
6289            >::empty()
6290            .ext(DataSchemaExtA { a: A(1) })
6291            .ext_with(|| DataSchemaExtB {
6292                d: B("hello".to_string()),
6293            })
6294            .finish_extend()
6295            .title("title")
6296            .object_ext(|b| {
6297                b.ext(ObjectSchemaExtA { c: A(2) })
6298                    .ext_with(|| ObjectSchemaExtB {
6299                        f: B("world".to_string()),
6300                    })
6301            })
6302            .property("x", false, |b| {
6303                b.ext(DataSchemaExtA { a: A(3) })
6304                    .ext(DataSchemaExtB {
6305                        d: B("other".to_string()),
6306                    })
6307                    .finish_extend()
6308                    .null()
6309            })
6310            .try_into()
6311            .unwrap();
6312
6313        assert_eq!(
6314            data_schema,
6315            DataSchema {
6316                title: Some("title".to_string()),
6317                other: Nil::cons(DataSchemaExtA { a: A(1) }).cons(DataSchemaExtB {
6318                    d: B("hello".to_string())
6319                }),
6320                subtype: Some(DataSchemaSubtype::Object(ObjectSchema {
6321                    other: Nil::cons(ObjectSchemaExtA { c: A(2) }).cons(ObjectSchemaExtB {
6322                        f: B("world".to_string())
6323                    }),
6324                    properties: Some(
6325                        [(
6326                            "x".to_string(),
6327                            DataSchema {
6328                                other: Nil::cons(DataSchemaExtA { a: A(3) }).cons(DataSchemaExtB {
6329                                    d: B("other".to_string())
6330                                }),
6331                                subtype: Some(DataSchemaSubtype::Null),
6332                                attype: Default::default(),
6333                                title: Default::default(),
6334                                titles: Default::default(),
6335                                description: Default::default(),
6336                                descriptions: Default::default(),
6337                                constant: Default::default(),
6338                                default: Default::default(),
6339                                unit: Default::default(),
6340                                one_of: Default::default(),
6341                                enumeration: Default::default(),
6342                                read_only: Default::default(),
6343                                write_only: Default::default(),
6344                                format: Default::default(),
6345                            }
6346                        )]
6347                        .into_iter()
6348                        .collect()
6349                    ),
6350                    required: None,
6351                })),
6352                attype: Default::default(),
6353                titles: Default::default(),
6354                description: Default::default(),
6355                descriptions: Default::default(),
6356                constant: Default::default(),
6357                default: Default::default(),
6358                unit: Default::default(),
6359                one_of: Default::default(),
6360                enumeration: Default::default(),
6361                read_only: Default::default(),
6362                write_only: Default::default(),
6363                format: Default::default(),
6364            }
6365        );
6366    }
6367
6368    #[test]
6369    fn valid_unchecked_tuple_data_schema() {
6370        let data_schema = UncheckedArraySchema::<Nil, Nil, Nil> {
6371            items: Some(BoxedElemOrVec::Vec(vec![
6372                UncheckedDataSchema {
6373                    titles: Some({
6374                        let mut multilang = MultiLanguageBuilder::default();
6375                        multilang.add("it", "title1").add("en", "title2");
6376                        multilang
6377                    }),
6378                    descriptions: Some({
6379                        let mut multilang = MultiLanguageBuilder::default();
6380                        multilang
6381                            .add("it", "description1")
6382                            .add("en", "description2");
6383                        multilang
6384                    }),
6385                    ..Default::default()
6386                },
6387                UncheckedDataSchema {
6388                    titles: Some({
6389                        let mut multilang = MultiLanguageBuilder::default();
6390                        multilang.add("it", "title3").add("en", "title4");
6391                        multilang
6392                    }),
6393                    descriptions: Some({
6394                        let mut multilang = MultiLanguageBuilder::default();
6395                        multilang
6396                            .add("it", "description3")
6397                            .add("en", "description4");
6398                        multilang
6399                    }),
6400                    ..Default::default()
6401                },
6402            ])),
6403            ..Default::default()
6404        };
6405
6406        assert_eq!(
6407            ArraySchema::try_from(data_schema).unwrap(),
6408            ArraySchema {
6409                items: Some(BoxedElemOrVec::Vec(vec![
6410                    DataSchema {
6411                        titles: Some(
6412                            [
6413                                ("it".parse().unwrap(), "title1".to_string()),
6414                                ("en".parse().unwrap(), "title2".to_string())
6415                            ]
6416                            .into_iter()
6417                            .collect()
6418                        ),
6419                        descriptions: Some(
6420                            [
6421                                ("it".parse().unwrap(), "description1".to_string()),
6422                                ("en".parse().unwrap(), "description2".to_string())
6423                            ]
6424                            .into_iter()
6425                            .collect()
6426                        ),
6427                        ..Default::default()
6428                    },
6429                    DataSchema {
6430                        titles: Some(
6431                            [
6432                                ("it".parse().unwrap(), "title3".to_string()),
6433                                ("en".parse().unwrap(), "title4".to_string())
6434                            ]
6435                            .into_iter()
6436                            .collect()
6437                        ),
6438                        descriptions: Some(
6439                            [
6440                                ("it".parse().unwrap(), "description3".to_string()),
6441                                ("en".parse().unwrap(), "description4".to_string())
6442                            ]
6443                            .into_iter()
6444                            .collect()
6445                        ),
6446                        ..Default::default()
6447                    },
6448                ])),
6449                ..Default::default()
6450            }
6451        );
6452    }
6453
6454    #[test]
6455    fn invalid_unchecked_tuple_data_schema() {
6456        let data_schema = UncheckedArraySchema::<Nil, Nil, Nil> {
6457            items: Some(BoxedElemOrVec::Vec(vec![
6458                UncheckedDataSchema {
6459                    titles: Some({
6460                        let mut multilang = MultiLanguageBuilder::default();
6461                        multilang.add("it", "title1").add("en", "title2");
6462                        multilang
6463                    }),
6464                    descriptions: Some({
6465                        let mut multilang = MultiLanguageBuilder::default();
6466                        multilang
6467                            .add("it", "description1")
6468                            .add("en", "description2");
6469                        multilang
6470                    }),
6471                    ..Default::default()
6472                },
6473                UncheckedDataSchema {
6474                    titles: Some({
6475                        let mut multilang = MultiLanguageBuilder::default();
6476                        multilang.add("it", "title3").add("en", "title4");
6477                        multilang
6478                    }),
6479                    descriptions: Some({
6480                        let mut multilang = MultiLanguageBuilder::default();
6481                        multilang
6482                            .add("it", "description3")
6483                            .add("e1n", "description4");
6484                        multilang
6485                    }),
6486                    ..Default::default()
6487                },
6488            ])),
6489            ..Default::default()
6490        };
6491
6492        assert_eq!(
6493            ArraySchema::try_from(data_schema).unwrap_err(),
6494            Error::InvalidLanguageTag("e1n".to_string()),
6495        );
6496    }
6497
6498    #[test]
6499    fn valid_unchecked_vec_data_schema() {
6500        let data_schema = UncheckedArraySchema::<Nil, Nil, Nil> {
6501            items: Some(BoxedElemOrVec::Elem(Box::new(UncheckedDataSchema {
6502                titles: Some({
6503                    let mut multilang = MultiLanguageBuilder::default();
6504                    multilang.add("it", "title1").add("en", "title2");
6505                    multilang
6506                }),
6507                descriptions: Some({
6508                    let mut multilang = MultiLanguageBuilder::default();
6509                    multilang
6510                        .add("it", "description1")
6511                        .add("en", "description2");
6512                    multilang
6513                }),
6514                ..Default::default()
6515            }))),
6516            min_items: Some(1),
6517            ..Default::default()
6518        };
6519
6520        assert_eq!(
6521            ArraySchema::try_from(data_schema).unwrap(),
6522            ArraySchema {
6523                items: Some(BoxedElemOrVec::Elem(Box::new(DataSchema {
6524                    titles: Some(
6525                        [
6526                            ("it".parse().unwrap(), "title1".to_string()),
6527                            ("en".parse().unwrap(), "title2".to_string())
6528                        ]
6529                        .into_iter()
6530                        .collect()
6531                    ),
6532                    descriptions: Some(
6533                        [
6534                            ("it".parse().unwrap(), "description1".to_string()),
6535                            ("en".parse().unwrap(), "description2".to_string())
6536                        ]
6537                        .into_iter()
6538                        .collect()
6539                    ),
6540                    ..Default::default()
6541                },))),
6542                min_items: Some(1),
6543                ..Default::default()
6544            }
6545        );
6546    }
6547
6548    #[test]
6549    fn invalid_unchecked_vec_data_schema() {
6550        let data_schema = UncheckedArraySchema::<Nil, Nil, Nil> {
6551            items: Some(BoxedElemOrVec::Elem(Box::new(UncheckedDataSchema {
6552                titles: Some({
6553                    let mut multilang = MultiLanguageBuilder::default();
6554                    multilang.add("it", "title1").add("en", "title2");
6555                    multilang
6556                }),
6557                descriptions: Some({
6558                    let mut multilang = MultiLanguageBuilder::default();
6559                    multilang
6560                        .add("it", "description1")
6561                        .add("e1n", "description2");
6562                    multilang
6563                }),
6564                ..Default::default()
6565            }))),
6566            min_items: Some(1),
6567            ..Default::default()
6568        };
6569
6570        assert_eq!(
6571            ArraySchema::try_from(data_schema).unwrap_err(),
6572            Error::InvalidLanguageTag("e1n".to_string()),
6573        );
6574    }
6575
6576    #[test]
6577    fn valid_unchecked_object_data_schema() {
6578        let data_schema = UncheckedObjectSchema::<Nil, Nil, Nil> {
6579            properties: Some(
6580                [
6581                    (
6582                        "data1".to_string(),
6583                        UncheckedDataSchema {
6584                            titles: Some({
6585                                let mut multilang = MultiLanguageBuilder::default();
6586                                multilang.add("it", "title1").add("en", "title2");
6587                                multilang
6588                            }),
6589                            descriptions: Some({
6590                                let mut multilang = MultiLanguageBuilder::default();
6591                                multilang
6592                                    .add("it", "description1")
6593                                    .add("en", "description2");
6594                                multilang
6595                            }),
6596                            ..Default::default()
6597                        },
6598                    ),
6599                    (
6600                        "data2".to_string(),
6601                        UncheckedDataSchema {
6602                            titles: Some({
6603                                let mut multilang = MultiLanguageBuilder::default();
6604                                multilang.add("it", "title3").add("en", "title4");
6605                                multilang
6606                            }),
6607                            descriptions: Some({
6608                                let mut multilang = MultiLanguageBuilder::default();
6609                                multilang
6610                                    .add("it", "description3")
6611                                    .add("en", "description4");
6612                                multilang
6613                            }),
6614                            ..Default::default()
6615                        },
6616                    ),
6617                ]
6618                .into_iter()
6619                .collect(),
6620            ),
6621            ..Default::default()
6622        };
6623
6624        assert_eq!(
6625            ObjectSchema::try_from(data_schema).unwrap(),
6626            ObjectSchema {
6627                properties: Some(
6628                    [
6629                        (
6630                            "data1".to_string(),
6631                            DataSchema {
6632                                titles: Some(
6633                                    [
6634                                        ("it".parse().unwrap(), "title1".to_string()),
6635                                        ("en".parse().unwrap(), "title2".to_string())
6636                                    ]
6637                                    .into_iter()
6638                                    .collect()
6639                                ),
6640                                descriptions: Some(
6641                                    [
6642                                        ("it".parse().unwrap(), "description1".to_string()),
6643                                        ("en".parse().unwrap(), "description2".to_string())
6644                                    ]
6645                                    .into_iter()
6646                                    .collect()
6647                                ),
6648                                ..Default::default()
6649                            }
6650                        ),
6651                        (
6652                            "data2".to_string(),
6653                            DataSchema {
6654                                titles: Some(
6655                                    [
6656                                        ("it".parse().unwrap(), "title3".to_string()),
6657                                        ("en".parse().unwrap(), "title4".to_string())
6658                                    ]
6659                                    .into_iter()
6660                                    .collect()
6661                                ),
6662                                descriptions: Some(
6663                                    [
6664                                        ("it".parse().unwrap(), "description3".to_string()),
6665                                        ("en".parse().unwrap(), "description4".to_string())
6666                                    ]
6667                                    .into_iter()
6668                                    .collect()
6669                                ),
6670                                ..Default::default()
6671                            }
6672                        ),
6673                    ]
6674                    .into_iter()
6675                    .collect()
6676                ),
6677                ..Default::default()
6678            }
6679        );
6680    }
6681
6682    #[test]
6683    fn invalid_unchecked_object_data_schema() {
6684        let data_schema = UncheckedObjectSchema::<Nil, Nil, Nil> {
6685            properties: Some(
6686                [
6687                    (
6688                        "data1".to_string(),
6689                        UncheckedDataSchema {
6690                            titles: Some({
6691                                let mut multilang = MultiLanguageBuilder::default();
6692                                multilang.add("it", "title1").add("en", "title2");
6693                                multilang
6694                            }),
6695                            descriptions: Some({
6696                                let mut multilang = MultiLanguageBuilder::default();
6697                                multilang
6698                                    .add("it", "description1")
6699                                    .add("en", "description2");
6700                                multilang
6701                            }),
6702                            ..Default::default()
6703                        },
6704                    ),
6705                    (
6706                        "data2".to_string(),
6707                        UncheckedDataSchema {
6708                            titles: Some({
6709                                let mut multilang = MultiLanguageBuilder::default();
6710                                multilang.add("it", "title3").add("en", "title4");
6711                                multilang
6712                            }),
6713                            descriptions: Some({
6714                                let mut multilang = MultiLanguageBuilder::default();
6715                                multilang
6716                                    .add("i1t", "description3")
6717                                    .add("en", "description4");
6718                                multilang
6719                            }),
6720                            ..Default::default()
6721                        },
6722                    ),
6723                ]
6724                .into_iter()
6725                .collect(),
6726            ),
6727            ..Default::default()
6728        };
6729
6730        assert_eq!(
6731            ObjectSchema::try_from(data_schema).unwrap_err(),
6732            Error::InvalidLanguageTag("i1t".to_string()),
6733        )
6734    }
6735
6736    #[test]
6737    fn valid_unchecked_data_schema() {
6738        let data_schema = UncheckedDataSchema::<Nil, Nil, Nil> {
6739            attype: Some(vec!["attype1".to_string(), "attype2".to_string()]),
6740            title: Some("title".to_string()),
6741            titles: Some({
6742                let mut multilang = MultiLanguageBuilder::default();
6743                multilang.add("it", "title1").add("en", "title2");
6744                multilang
6745            }),
6746            description: Some("description".to_string()),
6747            descriptions: Some({
6748                let mut multilang = MultiLanguageBuilder::default();
6749                multilang
6750                    .add("it", "description1")
6751                    .add("en", "description2");
6752                multilang
6753            }),
6754            unit: Some("unit".to_string()),
6755            read_only: true,
6756            write_only: true,
6757            format: Some("format".to_string()),
6758            subtype: Some(UncheckedDataSchemaSubtype::Number(NumberSchema {
6759                maximum: Some(Maximum::Inclusive(5.)),
6760                ..Default::default()
6761            })),
6762            ..Default::default()
6763        };
6764
6765        assert_eq!(
6766            DataSchema::try_from(data_schema).unwrap(),
6767            DataSchema {
6768                attype: Some(vec!["attype1".to_string(), "attype2".to_string()]),
6769                title: Some("title".to_string()),
6770                titles: Some(
6771                    [
6772                        ("it".parse().unwrap(), "title1".to_string()),
6773                        ("en".parse().unwrap(), "title2".to_string())
6774                    ]
6775                    .into_iter()
6776                    .collect()
6777                ),
6778                description: Some("description".to_string()),
6779                descriptions: Some(
6780                    [
6781                        ("it".parse().unwrap(), "description1".to_string()),
6782                        ("en".parse().unwrap(), "description2".to_string())
6783                    ]
6784                    .into_iter()
6785                    .collect()
6786                ),
6787                unit: Some("unit".to_string()),
6788                read_only: true,
6789                write_only: true,
6790                format: Some("format".to_string()),
6791                subtype: Some(DataSchemaSubtype::Number(NumberSchema {
6792                    maximum: Some(Maximum::Inclusive(5.)),
6793                    ..Default::default()
6794                })),
6795                ..Default::default()
6796            }
6797        );
6798    }
6799
6800    #[test]
6801    fn invalid_unchecked_data_schema() {
6802        let data_schema = UncheckedDataSchema::<Nil, Nil, Nil> {
6803            attype: Some(vec!["attype1".to_string(), "attype2".to_string()]),
6804            title: Some("title".to_string()),
6805            titles: Some({
6806                let mut multilang = MultiLanguageBuilder::default();
6807                multilang.add("it", "title1").add("en", "title2");
6808                multilang
6809            }),
6810            description: Some("description".to_string()),
6811            descriptions: Some({
6812                let mut multilang = MultiLanguageBuilder::default();
6813                multilang
6814                    .add("i1t", "description1")
6815                    .add("en", "description2");
6816                multilang
6817            }),
6818            unit: Some("unit".to_string()),
6819            read_only: true,
6820            write_only: true,
6821            format: Some("format".to_string()),
6822            subtype: Some(UncheckedDataSchemaSubtype::Number(NumberSchema {
6823                maximum: Some(Maximum::Inclusive(5.)),
6824                ..Default::default()
6825            })),
6826            ..Default::default()
6827        };
6828
6829        assert_eq!(
6830            DataSchema::try_from(data_schema).unwrap_err(),
6831            Error::InvalidLanguageTag("i1t".to_string()),
6832        );
6833    }
6834}