wot_td/
extend.rs

1//! Structured extensions for building and parsing Thing Descriptions
2//!
3//! The Thing Description can be extended with additional ontologies using its JSON-LD [@context](https://www.w3.org/TR/json-ld11/#the-context).
4//!
5//! This module provides a trait, [ExtendableThing], to define extensions for each of the standard
6//! elements of a description.
7
8use serde::{Deserialize, Serialize};
9
10use crate::hlist::{Cons, Nil};
11
12/// Requirement trait for extending a Thing Description element
13pub trait ExtendablePiece: Serialize + for<'a> Deserialize<'a> {}
14
15impl<T> ExtendablePiece for T where T: Serialize + for<'a> Deserialize<'a> {}
16
17/// Main extension trait
18///
19/// The trait uses an associated type for each element of the ThingDescription, set it to `()` if
20/// the extension does not apply to that specific element.
21pub trait ExtendableThing {
22    /// The extension type for [`InteractionAffordance`].
23    ///
24    /// [`InteractionAffordance`]: crate::thing::InteractionAffordance
25    type InteractionAffordance: ExtendablePiece;
26
27    /// The extension type for [`PropertyAffordance`].
28    ///
29    /// [`PropertyAffordance`]: crate::thing::PropertyAffordance
30    type PropertyAffordance: ExtendablePiece;
31
32    /// The extension type for [`ActionAffordance`].
33    ///
34    /// [`ActionAffordance`]: crate::thing::ActionAffordance
35    type ActionAffordance: ExtendablePiece;
36
37    /// The extension type for [`EventAffordance`].
38    ///
39    /// [`EventAffordance`]: crate::thing::EventAffordance
40    type EventAffordance: ExtendablePiece;
41
42    /// The extension type for [`Form`].
43    ///
44    /// [`Form`]: crate::thing::Form
45    type Form: ExtendablePiece;
46
47    /// The extension type for [`ExpectedResponse`].
48    ///
49    /// [`ExpectedResponse`]: crate::thing::ExpectedResponse
50    type ExpectedResponse: ExtendablePiece;
51
52    /// The extension type for [`DataSchema`].
53    ///
54    /// [`DataSchema`]: crate::thing::DataSchema
55    type DataSchema: ExtendablePiece;
56
57    /// The extension type for [`ObjectSchema`].
58    ///
59    /// [`ObjectSchema`]: crate::thing::ObjectSchema
60    type ObjectSchema: ExtendablePiece;
61
62    /// The extension type for [`ArraySchema`].
63    ///
64    /// [`ArraySchema`]: crate::thing::ArraySchema
65    type ArraySchema: ExtendablePiece;
66}
67
68impl ExtendableThing for Nil {
69    type InteractionAffordance = Nil;
70    type PropertyAffordance = Nil;
71    type ActionAffordance = Nil;
72    type EventAffordance = Nil;
73    type Form = Nil;
74    type ExpectedResponse = Nil;
75    type DataSchema = Nil;
76    type ObjectSchema = Nil;
77    type ArraySchema = Nil;
78}
79
80impl<T, U> ExtendableThing for Cons<T, U>
81where
82    T: ExtendableThing,
83    U: ExtendableThing,
84{
85    type InteractionAffordance = Cons<T::InteractionAffordance, U::InteractionAffordance>;
86    type PropertyAffordance = Cons<T::PropertyAffordance, U::PropertyAffordance>;
87    type ActionAffordance = Cons<T::ActionAffordance, U::ActionAffordance>;
88    type EventAffordance = Cons<T::EventAffordance, U::EventAffordance>;
89    type Form = Cons<T::Form, U::Form>;
90    type ExpectedResponse = Cons<T::ExpectedResponse, U::ExpectedResponse>;
91    type DataSchema = Cons<T::DataSchema, U::DataSchema>;
92    type ObjectSchema = Cons<T::ObjectSchema, U::ObjectSchema>;
93    type ArraySchema = Cons<T::ArraySchema, U::ArraySchema>;
94}
95
96/// A trait representing an object that can be created empty in order to extend a `Thing`.
97///
98/// This is separated from the [`Extend`] trait because it is not generic and it only contains an
99/// associate type.
100pub trait Extendable {
101    /// The empty extension type.
102    type Empty;
103
104    /// Create an empty extension
105    fn empty() -> Self::Empty;
106}
107
108/// A generic trait to express an object to extend a `Thing`.
109///
110/// This trait represents an object that can be _extended_ with other typed expressions. It is used
111/// extensively for all the _extendable_ types of a `Thing`.
112///
113/// The generic type `T` is the type that can be _added_ to the implemented `struct`/`enum`.
114///
115/// The trait is generally used in combination with the [`Extendable`] trait.
116pub trait Extend<T>: Sized {
117    /// The new type obtained when extending `Self`.
118    type Target;
119
120    /// Extend the current extension with an additional element
121    fn ext(self, t: T) -> Self::Target;
122
123    /// Extends the current type, passing a closure that returns `T`.
124    fn ext_with<F>(self, f: F) -> Self::Target
125    where
126        F: FnOnce() -> T,
127    {
128        self.ext(f())
129    }
130}
131
132impl Extendable for Nil {
133    type Empty = Nil;
134
135    fn empty() -> Self {
136        Nil
137    }
138}
139
140impl<T> Extend<T> for Nil {
141    type Target = Cons<T, Nil>;
142
143    fn ext(self, t: T) -> Self::Target {
144        Nil::cons(t)
145    }
146}
147
148impl<T, U> Extendable for Cons<T, U> {
149    type Empty = Nil;
150
151    fn empty() -> Self::Empty {
152        Nil
153    }
154}
155
156impl<T, U, V> Extend<T> for Cons<U, V> {
157    type Target = Cons<T, Cons<U, V>>;
158
159    fn ext(self, t: T) -> Self::Target {
160        self.cons(t)
161    }
162}