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}