1use alloc::{string::String, vec::Vec};
9use core::ops::Not;
10
11use hashbrown::HashMap;
12use serde_json::Value;
13
14use crate::{
15 extend::{Extend, Extendable, ExtendableThing},
16 thing::{
17 ActionAffordance, DataSchema, DefaultedFormOperations, EventAffordance, Form,
18 FormOperation, InteractionAffordance, PropertyAffordance, SecurityScheme,
19 },
20};
21
22use super::{
23 data_schema::{
24 buildable_data_schema_delegate, impl_inner_delegate_schema_builder_like_integer,
25 impl_inner_delegate_schema_builder_like_number,
26 impl_inner_delegate_schema_builder_like_object,
27 impl_inner_delegate_schema_builder_like_tuple, impl_inner_delegate_schema_builder_like_vec,
28 uri_variables_contains_arrays_objects, BuildableDataSchema, DataSchemaBuilder,
29 EnumerableDataSchema, IntegerDataSchemaBuilderLike, NumberDataSchemaBuilderLike,
30 ObjectDataSchemaBuilderLike, PartialDataSchema, PartialDataSchemaBuilder,
31 ReadableWriteableDataSchema, SpecializableDataSchema, TupleDataSchemaBuilderLike,
32 UncheckedDataSchemaFromOther, UncheckedDataSchemaMap, UnionDataSchema,
33 VecDataSchemaBuilderLike,
34 },
35 human_readable_info::{
36 impl_delegate_buildable_hr_info, BuildableHumanReadableInfo, HumanReadableInfo,
37 },
38 AffordanceType, Error, Extended, FormBuilder, MultiLanguageBuilder, ToExtend,
39};
40
41pub trait IntoUsable<T>: Sized {
46 fn into_usable(self) -> T;
48}
49
50pub(super) struct AffordanceBuilder<Affordance> {
51 pub(super) name: String,
52 pub(super) affordance: Affordance,
53}
54
55pub trait BuildableInteractionAffordance<Other: ExtendableThing> {
64 fn form<F, R>(self, f: F) -> Self
101 where
102 F: FnOnce(FormBuilder<Other, (), <Other::Form as Extendable>::Empty>) -> R,
103 R: Into<FormBuilder<Other, String, Other::Form>>,
104 Other::Form: Extendable;
105
106 fn uri_variable<F, T>(self, name: impl Into<String>, f: F) -> Self
148 where
149 F: FnOnce(
150 DataSchemaBuilder<
151 <Other::DataSchema as Extendable>::Empty,
152 Other::ArraySchema,
153 Other::ObjectSchema,
154 ToExtend,
155 >,
156 ) -> T,
157 T: Into<UncheckedDataSchemaFromOther<Other>>,
158 Other::DataSchema: Extendable;
159}
160
161pub(crate) struct PartialInteractionAffordanceBuilder<
166 Other: ExtendableThing,
167 OtherInteractionAffordance,
168> {
169 pub(super) forms: Vec<FormBuilder<Other, String, Other::Form>>,
170 pub(super) uri_variables: HashMap<String, UncheckedDataSchemaFromOther<Other>>,
171
172 pub other: OtherInteractionAffordance,
174}
175
176impl<Other, OtherInteractionAffordance> Default
177 for PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>
178where
179 Other: ExtendableThing,
180 OtherInteractionAffordance: Default,
181{
182 fn default() -> Self {
183 Self {
184 forms: Default::default(),
185 uri_variables: Default::default(),
186 other: Default::default(),
187 }
188 }
189}
190
191impl<Other>
192 PartialInteractionAffordanceBuilder<Other, <Other::InteractionAffordance as Extendable>::Empty>
193where
194 Other: ExtendableThing,
195 Other::InteractionAffordance: Extendable,
196{
197 pub(crate) fn empty() -> Self {
198 Self {
199 forms: Default::default(),
200 uri_variables: Default::default(),
201 other: Other::InteractionAffordance::empty(),
202 }
203 }
204}
205
206impl<Other: ExtendableThing, OtherInteractionAffordance>
207 PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>
208{
209 fn ext_with<F, T>(
211 self,
212 f: F,
213 ) -> PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance::Target>
214 where
215 OtherInteractionAffordance: Extend<T>,
216 F: FnOnce() -> T,
217 {
218 let Self {
219 forms,
220 uri_variables,
221 other,
222 } = self;
223 let other = other.ext_with(f);
224 PartialInteractionAffordanceBuilder {
225 forms,
226 uri_variables,
227 other,
228 }
229 }
230}
231
232impl<Other, OtherInteractionAffordance>
233 IntoUsable<PartialInteractionAffordanceBuilder<Other, Other::InteractionAffordance>>
234 for PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>
235where
236 Other: ExtendableThing,
237 OtherInteractionAffordance: Into<Other::InteractionAffordance>,
238{
239 fn into_usable(
240 self,
241 ) -> PartialInteractionAffordanceBuilder<Other, Other::InteractionAffordance> {
242 let Self {
243 forms,
244 uri_variables,
245 other,
246 } = self;
247
248 let other = other.into();
249 PartialInteractionAffordanceBuilder {
250 forms,
251 uri_variables,
252 other,
253 }
254 }
255}
256
257#[derive(Default)]
259pub(crate) struct InteractionAffordanceBuilder<Other: ExtendableThing, OtherInteractionAffordance> {
260 pub(super) partial: PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>,
261 pub(super) info: HumanReadableInfo,
262}
263
264impl<Other: ExtendableThing, OtherInteractionAffordance>
265 InteractionAffordanceBuilder<Other, OtherInteractionAffordance>
266{
267 pub(crate) fn ext_with<F, T>(
269 self,
270 f: F,
271 ) -> InteractionAffordanceBuilder<Other, OtherInteractionAffordance::Target>
272 where
273 OtherInteractionAffordance: Extend<T>,
274 F: FnOnce() -> T,
275 {
276 let Self { partial, info } = self;
277 let partial = partial.ext_with(f);
278 InteractionAffordanceBuilder { partial, info }
279 }
280
281 #[cfg(test)]
283 #[inline]
284 pub(crate) fn ext<T>(
285 self,
286 t: T,
287 ) -> InteractionAffordanceBuilder<Other, OtherInteractionAffordance::Target>
288 where
289 OtherInteractionAffordance: Extend<T>,
290 {
291 self.ext_with(|| t)
292 }
293}
294
295impl<Other> InteractionAffordanceBuilder<Other, Other::InteractionAffordance>
296where
297 Other: ExtendableThing,
298 Other::InteractionAffordance: Extendable,
299{
300 pub(crate) fn empty(
301 ) -> InteractionAffordanceBuilder<Other, <Other::InteractionAffordance as Extendable>::Empty>
302 {
303 InteractionAffordanceBuilder {
304 partial: PartialInteractionAffordanceBuilder::empty(),
305 info: Default::default(),
306 }
307 }
308}
309
310impl<Other, OtherInteractionAffordance> BuildableInteractionAffordance<Other>
311 for PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>
312where
313 Other: ExtendableThing,
314 Other::Form: Extendable,
315{
316 fn form<F, R>(mut self, f: F) -> Self
317 where
318 F: FnOnce(FormBuilder<Other, (), <Other::Form as Extendable>::Empty>) -> R,
319 R: Into<FormBuilder<Other, String, Other::Form>>,
320 {
321 self.forms.push(f(FormBuilder::new()).into());
322 self
323 }
324
325 fn uri_variable<F, T>(mut self, name: impl Into<String>, f: F) -> Self
326 where
327 F: FnOnce(
328 DataSchemaBuilder<
329 <Other::DataSchema as Extendable>::Empty,
330 Other::ArraySchema,
331 Other::ObjectSchema,
332 ToExtend,
333 >,
334 ) -> T,
335 T: Into<UncheckedDataSchemaFromOther<Other>>,
336 Other::DataSchema: Extendable,
337 {
338 self.uri_variables.insert(
339 name.into(),
340 f(DataSchemaBuilder::<Other::DataSchema, _, _, _>::empty()).into(),
341 );
342 self
343 }
344}
345
346macro_rules! impl_buildable_interaction_affordance {
347 ($($ty:ident $( <$($generic:ident $(: $bound:path)?),+> )? on $($interaction_path:ident).+),+ $(,)?) => {
348 $(
349 impl $(< $($generic $(: $bound)?),+ >)? BuildableInteractionAffordance<Other> for $ty $(< $($generic),+ >)?
350 where
351 Other::Form: Extendable
352 {
353 fn form<F, R>(mut self, f: F) -> Self
354 where
355 F: FnOnce(FormBuilder<Other, (), <Other::Form as Extendable>::Empty>) -> R,
356 R: Into<FormBuilder<Other, String, Other::Form>>,
357 Other::Form: Extendable,
358 {
359 self.$($interaction_path).* = self.$($interaction_path).*.form(f);
360 self
361 }
362
363 fn uri_variable<F, T>(mut self, name: impl Into<String>, f: F) -> Self
364 where
365 F: FnOnce(DataSchemaBuilder<<Other::DataSchema as Extendable>::Empty, Other::ArraySchema, Other::ObjectSchema, ToExtend>) -> T,
366 T: Into<UncheckedDataSchemaFromOther<Other>>,
367 Other::DataSchema: Extendable,
368 {
369 self.$($interaction_path).* = self.$($interaction_path).*.uri_variable(name, f);
370 self
371 }
372 }
373 )+
374 };
375}
376
377impl_buildable_interaction_affordance!(
378 InteractionAffordanceBuilder<Other: ExtendableThing, OtherInteractionAffordance> on partial,
379 PropertyAffordanceBuilder<Other: ExtendableThing, DS, OtherInteractionAffordance, OtherPropertyAffordance> on interaction,
380 ActionAffordanceBuilder<Other: ExtendableThing, OtherInteractionAffordance, OtherActionAffordance> on interaction.partial,
381 EventAffordanceBuilder<Other: ExtendableThing, OtherInteractionAffordance, OtherEventAffordance> on interaction.partial,
382);
383
384pub struct PropertyAffordanceBuilder<
529 Other: ExtendableThing,
530 DataSchema,
531 OtherInteractionAffordance,
532 OtherPropertyAffordance,
533> {
534 pub(super) interaction: PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>,
535 pub(super) info: HumanReadableInfo,
536 pub(super) data_schema: DataSchema,
537 pub(super) observable: Option<bool>,
538
539 pub other: OtherPropertyAffordance,
541}
542
543impl<Other, DataSchema, OtherInteractionAffordance, OtherPropertyAffordance> Default
544 for PropertyAffordanceBuilder<
545 Other,
546 DataSchema,
547 OtherInteractionAffordance,
548 OtherPropertyAffordance,
549 >
550where
551 Other: ExtendableThing,
552 PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>: Default,
553 DataSchema: Default,
554 OtherPropertyAffordance: Default,
555{
556 fn default() -> Self {
557 Self {
558 interaction: Default::default(),
559 info: Default::default(),
560 data_schema: Default::default(),
561 observable: Default::default(),
562 other: Default::default(),
563 }
564 }
565}
566
567pub struct ActionAffordanceBuilder<
702 Other: ExtendableThing,
703 OtherInteractionAffordance,
704 OtherActionAffordance,
705> {
706 pub(super) interaction: InteractionAffordanceBuilder<Other, OtherInteractionAffordance>,
707 pub(super) input: Option<UncheckedDataSchemaFromOther<Other>>,
708 pub(super) output: Option<UncheckedDataSchemaFromOther<Other>>,
709 pub(super) safe: bool,
710 pub(super) idempotent: bool,
711 pub(super) synchronous: Option<bool>,
712
713 pub other: OtherActionAffordance,
715}
716
717impl<Other, OtherInteractionAffordance, OtherActionAffordance> Default
718 for ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
719where
720 Other: ExtendableThing,
721 InteractionAffordanceBuilder<Other, OtherInteractionAffordance>: Default,
722 OtherActionAffordance: Default,
723{
724 fn default() -> Self {
725 Self {
726 interaction: Default::default(),
727 input: Default::default(),
728 output: Default::default(),
729 safe: Default::default(),
730 idempotent: Default::default(),
731 synchronous: Default::default(),
732 other: Default::default(),
733 }
734 }
735}
736
737impl<Other> ActionAffordanceBuilder<Other, Other::InteractionAffordance, Other::ActionAffordance>
738where
739 Other: ExtendableThing,
740 Other::InteractionAffordance: Extendable,
741 Other::ActionAffordance: Extendable,
742{
743 pub(crate) fn empty() -> ActionAffordanceBuilder<
744 Other,
745 <Other::InteractionAffordance as Extendable>::Empty,
746 <Other::ActionAffordance as Extendable>::Empty,
747 > {
748 ActionAffordanceBuilder {
749 interaction: InteractionAffordanceBuilder::empty(),
750 input: Default::default(),
751 output: Default::default(),
752 safe: Default::default(),
753 idempotent: Default::default(),
754 synchronous: Default::default(),
755 other: Other::ActionAffordance::empty(),
756 }
757 }
758}
759
760#[derive(Default)]
893pub struct EventAffordanceBuilder<
894 Other: ExtendableThing,
895 OtherInteractionAffordance,
896 OtherEventAffordance,
897> {
898 pub(super) interaction: InteractionAffordanceBuilder<Other, OtherInteractionAffordance>,
899 pub(super) subscription: Option<UncheckedDataSchemaFromOther<Other>>,
900 pub(super) data: Option<UncheckedDataSchemaFromOther<Other>>,
901 pub(super) cancellation: Option<UncheckedDataSchemaFromOther<Other>>,
902 pub(super) data_response: Option<UncheckedDataSchemaFromOther<Other>>,
903
904 pub other: OtherEventAffordance,
906}
907
908type EmptyEventAffordanceBuilder<Other> = EventAffordanceBuilder<
909 Other,
910 <<Other as ExtendableThing>::InteractionAffordance as Extendable>::Empty,
911 <<Other as ExtendableThing>::EventAffordance as Extendable>::Empty,
912>;
913
914impl<Other> EventAffordanceBuilder<Other, Other::InteractionAffordance, Other::EventAffordance>
915where
916 Other: ExtendableThing,
917 Other::InteractionAffordance: Extendable,
918 Other::EventAffordance: Extendable,
919{
920 pub(crate) fn empty() -> EmptyEventAffordanceBuilder<Other> {
921 EventAffordanceBuilder {
922 interaction: InteractionAffordanceBuilder::empty(),
923 subscription: Default::default(),
924 data: Default::default(),
925 cancellation: Default::default(),
926 data_response: Default::default(),
927 other: Other::EventAffordance::empty(),
928 }
929 }
930}
931
932impl<Other, OtherInteractionAffordance, OtherEventAffordance>
933 IntoUsable<UsableEventAffordanceBuilder<Other>>
934 for EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
935where
936 Other: ExtendableThing,
937 OtherInteractionAffordance: Into<Other::InteractionAffordance>,
938 OtherEventAffordance: Into<Other::EventAffordance>,
939{
940 fn into_usable(self) -> UsableEventAffordanceBuilder<Other> {
941 let Self {
942 interaction,
943 subscription,
944 data,
945 cancellation,
946 data_response,
947 other,
948 } = self;
949
950 let interaction = {
951 let InteractionAffordanceBuilder {
952 partial:
953 PartialInteractionAffordanceBuilder {
954 forms,
955 uri_variables,
956 other,
957 },
958 info,
959 } = interaction;
960 let other = other.into();
961 let partial = PartialInteractionAffordanceBuilder {
962 forms,
963 uri_variables,
964 other,
965 };
966 InteractionAffordanceBuilder { partial, info }
967 };
968 let other = other.into();
969
970 UsableEventAffordanceBuilder {
971 interaction,
972 subscription,
973 data,
974 cancellation,
975 data_response,
976 other,
977 }
978 }
979}
980
981pub(super) type UsablePropertyAffordanceBuilder<Other> = PropertyAffordanceBuilder<
982 Other,
983 PartialDataSchema<
984 <Other as ExtendableThing>::DataSchema,
985 <Other as ExtendableThing>::ArraySchema,
986 <Other as ExtendableThing>::ObjectSchema,
987 >,
988 <Other as ExtendableThing>::InteractionAffordance,
989 <Other as ExtendableThing>::PropertyAffordance,
990>;
991pub(super) type UsableActionAffordanceBuilder<Other> = ActionAffordanceBuilder<
992 Other,
993 <Other as ExtendableThing>::InteractionAffordance,
994 <Other as ExtendableThing>::ActionAffordance,
995>;
996pub(super) type UsableEventAffordanceBuilder<Other> = EventAffordanceBuilder<
997 Other,
998 <Other as ExtendableThing>::InteractionAffordance,
999 <Other as ExtendableThing>::EventAffordance,
1000>;
1001
1002impl<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance, Status>
1003 BuildableDataSchema<Other::DataSchema, Other::ArraySchema, Other::ObjectSchema, Status>
1004 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1005where
1006 Other: ExtendableThing,
1007 CDS: BuildableDataSchema<Other::DataSchema, Other::ArraySchema, Other::ObjectSchema, Status>,
1008{
1009 #[inline]
1010 fn unit(mut self, value: impl Into<String>) -> Self {
1011 buildable_data_schema_delegate!(self.data_schema -> unit(value))
1012 }
1013
1014 #[inline]
1015 fn format(mut self, value: impl Into<String>) -> Self {
1016 buildable_data_schema_delegate!(self.data_schema -> format(value))
1017 }
1018
1019 #[inline]
1020 fn default_value(mut self, value: impl Into<Value>) -> Self {
1021 buildable_data_schema_delegate!(self.data_schema -> default_value(value))
1022 }
1023}
1024
1025impl_delegate_buildable_hr_info!(
1026 InteractionAffordanceBuilder<Other: ExtendableThing, OtherInteractionAffordance> on info,
1027 PropertyAffordanceBuilder<Other: ExtendableThing, DS, OtherInteractionAffordance, OtherPropertyAffordance> on info,
1028 ActionAffordanceBuilder<Other: ExtendableThing, OtherInteractionAffordance, OtherPropertyAffordance> on interaction,
1029 EventAffordanceBuilder<Other: ExtendableThing, Affordance, OtherPropertyAffordance> on interaction,
1030);
1031
1032impl<Other>
1033 PropertyAffordanceBuilder<
1034 Other,
1035 PartialDataSchemaBuilder<
1036 <Other::DataSchema as Extendable>::Empty,
1037 Other::ArraySchema,
1038 Other::ObjectSchema,
1039 ToExtend,
1040 >,
1041 <Other::InteractionAffordance as Extendable>::Empty,
1042 <Other::PropertyAffordance as Extendable>::Empty,
1043 >
1044where
1045 Other: ExtendableThing,
1046 Other::DataSchema: Extendable,
1047 Other::InteractionAffordance: Extendable,
1048 Other::PropertyAffordance: Extendable,
1049{
1050 pub(crate) fn empty() -> Self {
1051 Self {
1052 interaction: PartialInteractionAffordanceBuilder::empty(),
1053 info: Default::default(),
1054 data_schema: PartialDataSchemaBuilder::<Other::DataSchema, _, _, _>::empty(),
1055 observable: Default::default(),
1056 other: Other::PropertyAffordance::empty(),
1057 }
1058 }
1059}
1060
1061impl<Other: ExtendableThing, DS, OtherInteractionAffordance, OtherPropertyAffordance>
1062 PropertyAffordanceBuilder<Other, DS, OtherInteractionAffordance, OtherPropertyAffordance>
1063{
1064 pub fn ext_interaction_with<F, T>(
1066 self,
1067 f: F,
1068 ) -> PropertyAffordanceBuilder<
1069 Other,
1070 DS,
1071 OtherInteractionAffordance::Target,
1072 OtherPropertyAffordance,
1073 >
1074 where
1075 OtherInteractionAffordance: Extend<T>,
1076 F: FnOnce() -> T,
1077 {
1078 let Self {
1079 interaction,
1080 info,
1081 data_schema,
1082 observable,
1083 other,
1084 } = self;
1085 let interaction = interaction.ext_with(f);
1086 PropertyAffordanceBuilder {
1087 interaction,
1088 info,
1089 data_schema,
1090 observable,
1091 other,
1092 }
1093 }
1094
1095 #[inline]
1097 pub fn ext_interaction<T>(
1098 self,
1099 t: T,
1100 ) -> PropertyAffordanceBuilder<
1101 Other,
1102 DS,
1103 OtherInteractionAffordance::Target,
1104 OtherPropertyAffordance,
1105 >
1106 where
1107 OtherInteractionAffordance: Extend<T>,
1108 {
1109 self.ext_interaction_with(|| t)
1110 }
1111
1112 pub fn ext_with<F, T>(
1114 self,
1115 f: F,
1116 ) -> PropertyAffordanceBuilder<
1117 Other,
1118 DS,
1119 OtherInteractionAffordance,
1120 OtherPropertyAffordance::Target,
1121 >
1122 where
1123 OtherPropertyAffordance: Extend<T>,
1124 F: FnOnce() -> T,
1125 {
1126 let Self {
1127 interaction,
1128 info,
1129 data_schema,
1130 observable,
1131 other,
1132 } = self;
1133 let other = other.ext_with(f);
1134 PropertyAffordanceBuilder {
1135 interaction,
1136 info,
1137 data_schema,
1138 observable,
1139 other,
1140 }
1141 }
1142
1143 #[inline]
1145 pub fn ext<T>(
1146 self,
1147 t: T,
1148 ) -> PropertyAffordanceBuilder<
1149 Other,
1150 DS,
1151 OtherInteractionAffordance,
1152 OtherPropertyAffordance::Target,
1153 >
1154 where
1155 OtherPropertyAffordance: Extend<T>,
1156 {
1157 self.ext_with(|| t)
1158 }
1159}
1160
1161impl<Other, OtherInteractionAffordance, OtherPropertyAffordance, DS, AS, OS>
1162 PropertyAffordanceBuilder<
1163 Other,
1164 PartialDataSchemaBuilder<DS, AS, OS, ToExtend>,
1165 OtherInteractionAffordance,
1166 OtherPropertyAffordance,
1167 >
1168where
1169 Other: ExtendableThing,
1170{
1171 pub fn ext_data_schema_with<F, T>(
1173 self,
1174 f: F,
1175 ) -> PropertyAffordanceBuilder<
1176 Other,
1177 PartialDataSchemaBuilder<DS::Target, AS, OS, ToExtend>,
1178 OtherInteractionAffordance,
1179 OtherPropertyAffordance,
1180 >
1181 where
1182 F: FnOnce() -> T,
1183 DS: Extend<T>,
1184 {
1185 let Self {
1186 interaction,
1187 info,
1188 data_schema,
1189 observable,
1190 other,
1191 } = self;
1192 let data_schema = data_schema.ext_with(f);
1193 PropertyAffordanceBuilder {
1194 interaction,
1195 info,
1196 data_schema,
1197 observable,
1198 other,
1199 }
1200 }
1201
1202 #[inline]
1204 pub fn ext_data_schema<T>(
1205 self,
1206 t: T,
1207 ) -> PropertyAffordanceBuilder<
1208 Other,
1209 PartialDataSchemaBuilder<DS::Target, AS, OS, ToExtend>,
1210 OtherInteractionAffordance,
1211 OtherPropertyAffordance,
1212 >
1213 where
1214 DS: Extend<T>,
1215 {
1216 self.ext_data_schema_with(|| t)
1217 }
1218
1219 pub fn finish_extend_data_schema(
1221 self,
1222 ) -> PropertyAffordanceBuilder<
1223 Other,
1224 PartialDataSchemaBuilder<DS, AS, OS, Extended>,
1225 OtherInteractionAffordance,
1226 OtherPropertyAffordance,
1227 > {
1228 let Self {
1229 interaction,
1230 info,
1231 data_schema,
1232 observable,
1233 other,
1234 } = self;
1235 let data_schema = data_schema.finish_extend();
1236 PropertyAffordanceBuilder {
1237 interaction,
1238 info,
1239 data_schema,
1240 observable,
1241 other,
1242 }
1243 }
1244}
1245
1246impl<Other, OtherInteractionAffordance, OtherPropertyAffordance, DS, AS, OS>
1247 PropertyAffordanceBuilder<
1248 Other,
1249 DataSchemaBuilder<DS, AS, OS, ToExtend>,
1250 OtherInteractionAffordance,
1251 OtherPropertyAffordance,
1252 >
1253where
1254 Other: ExtendableThing,
1255{
1256 pub fn ext_data_schema_with<F, T>(
1258 self,
1259 f: F,
1260 ) -> PropertyAffordanceBuilder<
1261 Other,
1262 DataSchemaBuilder<DS::Target, AS, OS, ToExtend>,
1263 OtherInteractionAffordance,
1264 OtherPropertyAffordance,
1265 >
1266 where
1267 F: FnOnce() -> T,
1268 DS: Extend<T>,
1269 {
1270 let Self {
1271 interaction,
1272 info,
1273 data_schema,
1274 observable,
1275 other,
1276 } = self;
1277 let data_schema = data_schema.ext_with(f);
1278 PropertyAffordanceBuilder {
1279 interaction,
1280 info,
1281 data_schema,
1282 observable,
1283 other,
1284 }
1285 }
1286
1287 #[inline]
1289 pub fn ext_data_schema<T>(
1290 self,
1291 t: T,
1292 ) -> PropertyAffordanceBuilder<
1293 Other,
1294 DataSchemaBuilder<DS::Target, AS, OS, ToExtend>,
1295 OtherInteractionAffordance,
1296 OtherPropertyAffordance,
1297 >
1298 where
1299 DS: Extend<T>,
1300 {
1301 self.ext_data_schema_with(|| t)
1302 }
1303
1304 pub fn finish_extend_data_schema(
1306 self,
1307 ) -> PropertyAffordanceBuilder<
1308 Other,
1309 DataSchemaBuilder<DS, AS, OS, Extended>,
1310 OtherInteractionAffordance,
1311 OtherPropertyAffordance,
1312 > {
1313 let Self {
1314 interaction,
1315 info,
1316 data_schema,
1317 observable,
1318 other,
1319 } = self;
1320 let data_schema = data_schema.finish_extend();
1321 PropertyAffordanceBuilder {
1322 interaction,
1323 info,
1324 data_schema,
1325 observable,
1326 other,
1327 }
1328 }
1329}
1330
1331impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1332 IntoUsable<UsablePropertyAffordanceBuilder<Other>>
1333 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1334where
1335 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1336 CDS: Into<PartialDataSchema<DS, AS, OS>>,
1337 PartialInteractionAffordanceBuilder<Other, OtherInteractionAffordance>:
1338 IntoUsable<PartialInteractionAffordanceBuilder<Other, Other::InteractionAffordance>>,
1339 OtherPropertyAffordance: Into<Other::PropertyAffordance>,
1340{
1341 fn into_usable(self) -> UsablePropertyAffordanceBuilder<Other> {
1342 let Self {
1343 interaction,
1344 info,
1345 data_schema,
1346 observable,
1347 other,
1348 } = self;
1349
1350 let interaction = interaction.into_usable();
1351 let data_schema = data_schema.into();
1352 let other = other.into();
1353 PropertyAffordanceBuilder {
1354 interaction,
1355 info,
1356 data_schema,
1357 observable,
1358 other,
1359 }
1360 }
1361}
1362
1363impl<Other: ExtendableThing, OtherInteractionAffordance, OtherActionAffordance>
1364 ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
1365{
1366 pub fn ext_interaction_with<F, T>(
1368 self,
1369 f: F,
1370 ) -> ActionAffordanceBuilder<Other, OtherInteractionAffordance::Target, OtherActionAffordance>
1371 where
1372 OtherInteractionAffordance: Extend<T>,
1373 F: FnOnce() -> T,
1374 {
1375 let Self {
1376 interaction,
1377 input,
1378 output,
1379 safe,
1380 idempotent,
1381 synchronous,
1382 other,
1383 } = self;
1384 let interaction = interaction.ext_with(f);
1385 ActionAffordanceBuilder {
1386 interaction,
1387 input,
1388 output,
1389 safe,
1390 idempotent,
1391 synchronous,
1392 other,
1393 }
1394 }
1395
1396 #[inline]
1398 pub fn ext_interaction<T>(
1399 self,
1400 t: T,
1401 ) -> ActionAffordanceBuilder<Other, OtherInteractionAffordance::Target, OtherActionAffordance>
1402 where
1403 OtherInteractionAffordance: Extend<T>,
1404 {
1405 self.ext_interaction_with(|| t)
1406 }
1407
1408 pub fn ext_with<F, T>(
1410 self,
1411 f: F,
1412 ) -> ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance::Target>
1413 where
1414 OtherActionAffordance: Extend<T>,
1415 F: FnOnce() -> T,
1416 {
1417 let Self {
1418 interaction,
1419 input,
1420 output,
1421 safe,
1422 idempotent,
1423 synchronous,
1424 other,
1425 } = self;
1426 let other = other.ext_with(f);
1427 ActionAffordanceBuilder {
1428 interaction,
1429 input,
1430 output,
1431 safe,
1432 idempotent,
1433 synchronous,
1434 other,
1435 }
1436 }
1437
1438 #[inline]
1440 pub fn ext<T>(
1441 self,
1442 t: T,
1443 ) -> ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance::Target>
1444 where
1445 OtherActionAffordance: Extend<T>,
1446 {
1447 self.ext_with(|| t)
1448 }
1449}
1450
1451impl<Other: ExtendableThing, OtherInteractionAffordance, OtherEventAffordance>
1452 EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
1453{
1454 pub fn ext_interaction_with<F, T>(
1456 self,
1457 f: F,
1458 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance::Target, OtherEventAffordance>
1459 where
1460 OtherInteractionAffordance: Extend<T>,
1461 F: FnOnce() -> T,
1462 {
1463 let Self {
1464 interaction,
1465 subscription,
1466 data,
1467 cancellation,
1468 data_response,
1469 other,
1470 } = self;
1471 let interaction = interaction.ext_with(f);
1472 EventAffordanceBuilder {
1473 interaction,
1474 subscription,
1475 data,
1476 cancellation,
1477 data_response,
1478 other,
1479 }
1480 }
1481
1482 #[inline]
1484 pub fn ext_interaction<T>(
1485 self,
1486 t: T,
1487 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance::Target, OtherEventAffordance>
1488 where
1489 OtherInteractionAffordance: Extend<T>,
1490 {
1491 self.ext_interaction_with(|| t)
1492 }
1493
1494 pub fn ext_with<F, T>(
1496 self,
1497 f: F,
1498 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance::Target>
1499 where
1500 OtherEventAffordance: Extend<T>,
1501 F: FnOnce() -> T,
1502 {
1503 let Self {
1504 interaction,
1505 subscription,
1506 data,
1507 cancellation,
1508 data_response,
1509 other,
1510 } = self;
1511 let other = other.ext_with(f);
1512 EventAffordanceBuilder {
1513 interaction,
1514 subscription,
1515 data,
1516 cancellation,
1517 data_response,
1518 other,
1519 }
1520 }
1521
1522 #[inline]
1524 pub fn ext<T>(
1525 self,
1526 t: T,
1527 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance::Target>
1528 where
1529 OtherEventAffordance: Extend<T>,
1530 {
1531 self.ext_with(|| t)
1532 }
1533}
1534
1535impl<Other: ExtendableThing, DataSchema, OtherInteractionAffordance, OtherPropertyAffordance>
1536 PropertyAffordanceBuilder<
1537 Other,
1538 DataSchema,
1539 OtherInteractionAffordance,
1540 OtherPropertyAffordance,
1541 >
1542{
1543 pub fn observable(mut self, value: bool) -> Self {
1545 self.observable = Some(value);
1546 self
1547 }
1548}
1549
1550macro_rules! impl_property_affordance_builder_delegator {
1551 ($($name:ident $(< $($generic_def:ident),+ >)? $( ( $($arg:ident : $arg_ty:ty),+ ) )? $(where $($generic:ident : $bound:path),+)? => $ty:ty),+ $(,)?) => {
1552 $(
1553 fn $name $(<$($generic_def),+>)? (self $(, $($arg: $arg_ty),+)?) -> $ty
1554 $(
1555 where
1556 $($generic: $bound),+
1557 )?
1558 {
1559 let Self {
1560 interaction,
1561 info,
1562 data_schema,
1563 observable,
1564 other,
1565 } = self;
1566
1567 let data_schema = data_schema.$name($($($arg),+)?);
1568 PropertyAffordanceBuilder {
1569 interaction,
1570 info,
1571 data_schema,
1572 observable,
1573 other,
1574 }
1575 }
1576 )+
1577 };
1578}
1579
1580impl<Other, DataSchema, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1581 SpecializableDataSchema<DS, AS, OS>
1582 for PropertyAffordanceBuilder<
1583 Other,
1584 DataSchema,
1585 OtherInteractionAffordance,
1586 OtherPropertyAffordance,
1587 >
1588where
1589 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1590 DataSchema: SpecializableDataSchema<DS, AS, OS>,
1591{
1592 type Stateless = PropertyAffordanceBuilder<
1593 Other,
1594 DataSchema::Stateless,
1595 OtherInteractionAffordance,
1596 OtherPropertyAffordance,
1597 >;
1598 type Tuple = PropertyAffordanceBuilder<
1599 Other,
1600 DataSchema::Tuple,
1601 OtherInteractionAffordance,
1602 OtherPropertyAffordance,
1603 >;
1604 type Vec = PropertyAffordanceBuilder<
1605 Other,
1606 DataSchema::Vec,
1607 OtherInteractionAffordance,
1608 OtherPropertyAffordance,
1609 >;
1610 type Number = PropertyAffordanceBuilder<
1611 Other,
1612 DataSchema::Number,
1613 OtherInteractionAffordance,
1614 OtherPropertyAffordance,
1615 >;
1616 type Integer = PropertyAffordanceBuilder<
1617 Other,
1618 DataSchema::Integer,
1619 OtherInteractionAffordance,
1620 OtherPropertyAffordance,
1621 >;
1622 type Object = PropertyAffordanceBuilder<
1623 Other,
1624 DataSchema::Object,
1625 OtherInteractionAffordance,
1626 OtherPropertyAffordance,
1627 >;
1628 type String = PropertyAffordanceBuilder<
1629 Other,
1630 DataSchema::String,
1631 OtherInteractionAffordance,
1632 OtherPropertyAffordance,
1633 >;
1634 type Constant = PropertyAffordanceBuilder<
1635 Other,
1636 DataSchema::Constant,
1637 OtherInteractionAffordance,
1638 OtherPropertyAffordance,
1639 >;
1640
1641 impl_property_affordance_builder_delegator!(
1642 tuple where AS: Default => Self::Tuple,
1643 tuple_ext<F>(f: F) where F: FnOnce(AS::Empty) -> AS, AS: Extendable => Self::Tuple,
1644 vec where AS: Default => Self::Vec,
1645 vec_ext<F>(f: F) where F: FnOnce(AS::Empty) -> AS, AS: Extendable => Self::Vec,
1646 bool => Self::Stateless,
1647 number => Self::Number,
1648 integer => Self::Integer,
1649 object where OS: Default => Self::Object,
1650 object_ext<F>(f: F) where F: FnOnce(OS::Empty) -> OS, OS: Extendable => Self::Object,
1651 string => Self::String,
1652 null => Self::Stateless,
1653 constant(value: impl Into<Value>) => Self::Constant,
1654 );
1655}
1656
1657impl<Other, DataSchema, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1658 EnumerableDataSchema<DS, AS, OS, Extended>
1659 for PropertyAffordanceBuilder<
1660 Other,
1661 DataSchema,
1662 OtherInteractionAffordance,
1663 OtherPropertyAffordance,
1664 >
1665where
1666 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1667 DataSchema: EnumerableDataSchema<DS, AS, OS, Extended>,
1668{
1669 type Target = PropertyAffordanceBuilder<
1670 Other,
1671 DataSchema::Target,
1672 OtherInteractionAffordance,
1673 OtherPropertyAffordance,
1674 >;
1675
1676 fn enumeration(self, value: impl Into<Value>) -> Self::Target {
1677 let Self {
1678 interaction,
1679 info,
1680 data_schema,
1681 observable,
1682 other,
1683 } = self;
1684
1685 let data_schema = data_schema.enumeration(value);
1686
1687 PropertyAffordanceBuilder {
1688 interaction,
1689 info,
1690 data_schema,
1691 observable,
1692 other,
1693 }
1694 }
1695}
1696
1697impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1698 UnionDataSchema<DS, AS, OS>
1699 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1700where
1701 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1702 CDS: UnionDataSchema<DS, AS, OS>,
1703{
1704 type Target = PropertyAffordanceBuilder<
1705 Other,
1706 CDS::Target,
1707 OtherInteractionAffordance,
1708 OtherPropertyAffordance,
1709 >;
1710
1711 fn one_of<F, T>(self, f: F) -> Self::Target
1712 where
1713 F: FnOnce(
1714 DataSchemaBuilder<
1715 <DS as Extendable>::Empty,
1716 Other::ArraySchema,
1717 Other::ObjectSchema,
1718 ToExtend,
1719 >,
1720 ) -> T,
1721 DS: Extendable,
1722 T: Into<UncheckedDataSchemaFromOther<Other>>,
1723 {
1724 let Self {
1725 interaction,
1726 info,
1727 data_schema,
1728 observable,
1729 other,
1730 } = self;
1731
1732 let data_schema = data_schema.one_of(f);
1733 PropertyAffordanceBuilder {
1734 interaction,
1735 info,
1736 data_schema,
1737 observable,
1738 other,
1739 }
1740 }
1741}
1742
1743impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1744 ReadableWriteableDataSchema<DS, AS, OS, Extended>
1745 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1746where
1747 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1748 CDS: ReadableWriteableDataSchema<DS, AS, OS, Extended>,
1749{
1750 type ReadOnly = PropertyAffordanceBuilder<
1751 Other,
1752 CDS::ReadOnly,
1753 OtherInteractionAffordance,
1754 OtherPropertyAffordance,
1755 >;
1756 type WriteOnly = PropertyAffordanceBuilder<
1757 Other,
1758 CDS::WriteOnly,
1759 OtherInteractionAffordance,
1760 OtherPropertyAffordance,
1761 >;
1762
1763 fn read_only(self) -> Self::ReadOnly {
1764 let Self {
1765 interaction,
1766 info,
1767 data_schema,
1768 observable,
1769 other,
1770 } = self;
1771
1772 let data_schema = data_schema.read_only();
1773 PropertyAffordanceBuilder {
1774 interaction,
1775 info,
1776 data_schema,
1777 observable,
1778 other,
1779 }
1780 }
1781
1782 fn write_only(self) -> Self::WriteOnly {
1783 let Self {
1784 interaction,
1785 info,
1786 data_schema,
1787 observable,
1788 other,
1789 } = self;
1790
1791 let data_schema = data_schema.write_only();
1792 PropertyAffordanceBuilder {
1793 interaction,
1794 info,
1795 data_schema,
1796 observable,
1797 other,
1798 }
1799 }
1800}
1801
1802impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1803 TupleDataSchemaBuilderLike<DS, AS, OS>
1804 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1805where
1806 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1807 CDS: TupleDataSchemaBuilderLike<DS, AS, OS>,
1808{
1809 impl_inner_delegate_schema_builder_like_tuple!(data_schema);
1810}
1811
1812impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1813 VecDataSchemaBuilderLike<DS, AS, OS>
1814 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1815where
1816 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1817 CDS: VecDataSchemaBuilderLike<DS, AS, OS>,
1818{
1819 impl_inner_delegate_schema_builder_like_vec!(data_schema);
1820}
1821
1822impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1823 NumberDataSchemaBuilderLike<DS, AS, OS>
1824 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1825where
1826 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1827 CDS: NumberDataSchemaBuilderLike<DS, AS, OS>,
1828{
1829 impl_inner_delegate_schema_builder_like_number!(data_schema);
1830}
1831
1832impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1833 IntegerDataSchemaBuilderLike<DS, AS, OS>
1834 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1835where
1836 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1837 CDS: IntegerDataSchemaBuilderLike<DS, AS, OS>,
1838{
1839 impl_inner_delegate_schema_builder_like_integer!(data_schema);
1840}
1841
1842impl<Other, CDS, DS, AS, OS, OtherInteractionAffordance, OtherPropertyAffordance>
1843 ObjectDataSchemaBuilderLike<DS, AS, OS>
1844 for PropertyAffordanceBuilder<Other, CDS, OtherInteractionAffordance, OtherPropertyAffordance>
1845where
1846 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
1847 CDS: ObjectDataSchemaBuilderLike<DS, AS, OS>,
1848{
1849 impl_inner_delegate_schema_builder_like_object!(data_schema);
1850}
1851
1852impl<Other: ExtendableThing, OtherInteractionAffordance, OtherActionAffordance>
1853 ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
1854{
1855 pub fn input<F, T>(
1894 self,
1895 f: F,
1896 ) -> ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
1897 where
1898 F: FnOnce(
1899 DataSchemaBuilder<
1900 <Other::DataSchema as Extendable>::Empty,
1901 Other::ArraySchema,
1902 Other::ObjectSchema,
1903 ToExtend,
1904 >,
1905 ) -> T,
1906 T: Into<UncheckedDataSchemaFromOther<Other>>,
1907 Other::DataSchema: Extendable,
1908 {
1909 let Self {
1910 interaction,
1911 input: _,
1912 output,
1913 safe,
1914 idempotent,
1915 synchronous,
1916 other,
1917 } = self;
1918 let input = Some(f(DataSchemaBuilder::<Other::DataSchema, _, _, _>::empty()).into());
1919
1920 ActionAffordanceBuilder {
1921 interaction,
1922 input,
1923 output,
1924 safe,
1925 idempotent,
1926 synchronous,
1927 other,
1928 }
1929 }
1930}
1931
1932impl<Other: ExtendableThing, OtherInteractionAffordance, OtherActionAffordance>
1933 ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
1934{
1935 pub fn output<F, T>(
1974 self,
1975 f: F,
1976 ) -> ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
1977 where
1978 F: FnOnce(
1979 DataSchemaBuilder<
1980 <Other::DataSchema as Extendable>::Empty,
1981 Other::ArraySchema,
1982 Other::ObjectSchema,
1983 ToExtend,
1984 >,
1985 ) -> T,
1986 T: Into<UncheckedDataSchemaFromOther<Other>>,
1987 Other::DataSchema: Extendable,
1988 {
1989 let Self {
1990 interaction,
1991 input,
1992 output: _,
1993 safe,
1994 idempotent,
1995 synchronous,
1996 other,
1997 } = self;
1998 let output = Some(f(DataSchemaBuilder::<Other::DataSchema, _, _, _>::empty()).into());
1999
2000 ActionAffordanceBuilder {
2001 interaction,
2002 input,
2003 output,
2004 safe,
2005 idempotent,
2006 synchronous,
2007 other,
2008 }
2009 }
2010}
2011
2012impl<Other: ExtendableThing, OtherInteractionAffordance, OtherActionAffordance>
2013 ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
2014{
2015 pub fn safe(mut self) -> Self {
2017 self.safe = true;
2018 self
2019 }
2020
2021 pub fn idempotent(mut self) -> Self {
2023 self.idempotent = true;
2024 self
2025 }
2026
2027 pub fn synchronous(mut self, value: bool) -> Self {
2029 self.synchronous = Some(value);
2030 self
2031 }
2032}
2033
2034impl<Other: ExtendableThing, OtherInteractionAffordance, OtherEventAffordance>
2035 EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2036{
2037 pub fn subscription<F, T>(
2074 self,
2075 f: F,
2076 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2077 where
2078 F: FnOnce(
2079 DataSchemaBuilder<
2080 <Other::DataSchema as Extendable>::Empty,
2081 Other::ArraySchema,
2082 Other::ObjectSchema,
2083 ToExtend,
2084 >,
2085 ) -> T,
2086 T: Into<UncheckedDataSchemaFromOther<Other>>,
2087 Other::DataSchema: Extendable,
2088 {
2089 let Self {
2090 interaction,
2091 subscription: _,
2092 data,
2093 cancellation,
2094 data_response,
2095 other,
2096 } = self;
2097 let subscription = Some(f(DataSchemaBuilder::<Other::DataSchema, _, _, _>::empty()).into());
2098
2099 EventAffordanceBuilder {
2100 interaction,
2101 subscription,
2102 data,
2103 cancellation,
2104 data_response,
2105 other,
2106 }
2107 }
2108}
2109
2110impl<Other: ExtendableThing, OtherInteractionAffordance, OtherEventAffordance>
2111 EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2112{
2113 pub fn data<F, T>(
2150 self,
2151 f: F,
2152 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2153 where
2154 F: FnOnce(
2155 DataSchemaBuilder<
2156 <Other::DataSchema as Extendable>::Empty,
2157 Other::ArraySchema,
2158 Other::ObjectSchema,
2159 ToExtend,
2160 >,
2161 ) -> T,
2162 T: Into<UncheckedDataSchemaFromOther<Other>>,
2163 Other::DataSchema: Extendable,
2164 {
2165 let Self {
2166 interaction,
2167 subscription,
2168 data: _,
2169 cancellation,
2170 data_response,
2171 other,
2172 } = self;
2173 let data = Some(f(DataSchemaBuilder::<Other::DataSchema, _, _, _>::empty()).into());
2174
2175 EventAffordanceBuilder {
2176 interaction,
2177 subscription,
2178 data,
2179 cancellation,
2180 data_response,
2181 other,
2182 }
2183 }
2184}
2185
2186impl<Other: ExtendableThing, OtherInteractionAffordance, OtherEventAffordance>
2187 EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2188{
2189 pub fn cancellation<F, T>(
2226 self,
2227 f: F,
2228 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2229 where
2230 F: FnOnce(
2231 DataSchemaBuilder<
2232 <Other::DataSchema as Extendable>::Empty,
2233 Other::ArraySchema,
2234 Other::ObjectSchema,
2235 ToExtend,
2236 >,
2237 ) -> T,
2238 T: Into<UncheckedDataSchemaFromOther<Other>>,
2239 Other::DataSchema: Extendable,
2240 {
2241 let Self {
2242 interaction,
2243 subscription,
2244 data,
2245 cancellation: _,
2246 data_response,
2247 other,
2248 } = self;
2249 let cancellation = Some(f(DataSchemaBuilder::<Other::DataSchema, _, _, _>::empty()).into());
2250
2251 EventAffordanceBuilder {
2252 interaction,
2253 subscription,
2254 data,
2255 cancellation,
2256 data_response,
2257 other,
2258 }
2259 }
2260}
2261
2262impl<Other: ExtendableThing, OtherInteractionAffordance, OtherEventAffordance>
2263 EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2264{
2265 pub fn data_response<F, T>(
2302 self,
2303 f: F,
2304 ) -> EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2305 where
2306 F: FnOnce(
2307 DataSchemaBuilder<
2308 <Other::DataSchema as Extendable>::Empty,
2309 Other::ArraySchema,
2310 Other::ObjectSchema,
2311 ToExtend,
2312 >,
2313 ) -> T,
2314 T: Into<UncheckedDataSchemaFromOther<Other>>,
2315 Other::DataSchema: Extendable,
2316 {
2317 let Self {
2318 interaction,
2319 subscription,
2320 data,
2321 cancellation,
2322 data_response: _,
2323 other,
2324 } = self;
2325 let data_response =
2326 Some(f(DataSchemaBuilder::<Other::DataSchema, _, _, _>::empty()).into());
2327
2328 EventAffordanceBuilder {
2329 interaction,
2330 subscription,
2331 data,
2332 cancellation,
2333 data_response,
2334 other,
2335 }
2336 }
2337}
2338
2339impl<Other, OtherInteractionAffordance>
2340 From<InteractionAffordanceBuilder<Other, OtherInteractionAffordance>>
2341 for UncheckedInteractionAffordance<Other>
2342where
2343 Other: ExtendableThing,
2344 OtherInteractionAffordance: Into<Other::InteractionAffordance>,
2345{
2346 fn from(builder: InteractionAffordanceBuilder<Other, OtherInteractionAffordance>) -> Self {
2347 let InteractionAffordanceBuilder {
2348 info:
2349 HumanReadableInfo {
2350 attype,
2351 title,
2352 titles,
2353 description,
2354 descriptions,
2355 },
2356 partial:
2357 PartialInteractionAffordanceBuilder {
2358 forms,
2359 uri_variables,
2360 other,
2361 },
2362 } = builder;
2363
2364 let forms = forms.into_iter().map(Form::from).collect();
2365 let uri_variables = uri_variables.is_empty().not().then_some(uri_variables);
2366 let other = other.into();
2367
2368 Self {
2369 attype,
2370 title,
2371 titles,
2372 description,
2373 descriptions,
2374 forms,
2375 uri_variables,
2376 other,
2377 }
2378 }
2379}
2380
2381impl<Other: ExtendableThing, OtherInteractionAffordance, OtherActionAffordance>
2382 IntoUsable<UsableActionAffordanceBuilder<Other>>
2383 for ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
2384where
2385 OtherInteractionAffordance: Into<Other::InteractionAffordance>,
2386 OtherActionAffordance: Into<Other::ActionAffordance>,
2387{
2388 fn into_usable(self) -> UsableActionAffordanceBuilder<Other> {
2389 let ActionAffordanceBuilder {
2390 interaction,
2391 input,
2392 output,
2393 safe,
2394 idempotent,
2395 synchronous,
2396 other,
2397 } = self;
2398
2399 let interaction = {
2400 let InteractionAffordanceBuilder {
2401 partial:
2402 PartialInteractionAffordanceBuilder {
2403 forms,
2404 uri_variables,
2405 other,
2406 },
2407 info,
2408 } = interaction;
2409 let other = other.into();
2410 let partial = PartialInteractionAffordanceBuilder {
2411 forms,
2412 uri_variables,
2413 other,
2414 };
2415 InteractionAffordanceBuilder { partial, info }
2416 };
2417
2418 let other = other.into();
2419
2420 UsableActionAffordanceBuilder {
2421 interaction,
2422 input,
2423 output,
2424 safe,
2425 idempotent,
2426 synchronous,
2427 other,
2428 }
2429 }
2430}
2431
2432pub(super) trait CheckableInteractionAffordanceBuilder {
2433 fn check<F>(
2434 &self,
2435 security_definitions: &HashMap<String, SecurityScheme>,
2436 affordance_type: AffordanceType,
2437 is_allowed_op: F,
2438 ) -> Result<(), Error>
2439 where
2440 F: Fn(FormOperation) -> bool;
2441}
2442
2443impl<Other: ExtendableThing> CheckableInteractionAffordanceBuilder
2444 for PartialInteractionAffordanceBuilder<Other, Other::InteractionAffordance>
2445{
2446 fn check<F>(
2447 &self,
2448 security_definitions: &HashMap<String, SecurityScheme>,
2449 affordance_type: AffordanceType,
2450 is_allowed_op: F,
2451 ) -> Result<(), Error>
2452 where
2453 F: Fn(FormOperation) -> bool,
2454 {
2455 check_form_builders(
2456 &self.forms,
2457 security_definitions,
2458 affordance_type,
2459 is_allowed_op,
2460 )?;
2461 if uri_variables_contains_arrays_objects::<Other>(&self.uri_variables) {
2462 return Err(Error::InvalidUriVariables);
2463 }
2464
2465 Ok(())
2466 }
2467}
2468
2469impl<Other: ExtendableThing> CheckableInteractionAffordanceBuilder
2470 for InteractionAffordanceBuilder<Other, Other::InteractionAffordance>
2471{
2472 fn check<F>(
2473 &self,
2474 security_definitions: &HashMap<String, SecurityScheme>,
2475 affordance_type: AffordanceType,
2476 is_allowed_op: F,
2477 ) -> Result<(), Error>
2478 where
2479 F: Fn(FormOperation) -> bool,
2480 {
2481 check_form_builders(
2482 &self.partial.forms,
2483 security_definitions,
2484 affordance_type,
2485 is_allowed_op,
2486 )?;
2487 if uri_variables_contains_arrays_objects::<Other>(&self.partial.uri_variables) {
2488 return Err(Error::InvalidUriVariables);
2489 }
2490
2491 Ok(())
2492 }
2493}
2494
2495pub(super) fn check_form_builders<Other, F>(
2496 forms: &[FormBuilder<Other, String, Other::Form>],
2497 security_definitions: &HashMap<String, SecurityScheme>,
2498 affordance_type: AffordanceType,
2499 is_allowed_op: F,
2500) -> Result<(), Error>
2501where
2502 Other: ExtendableThing,
2503 F: Fn(FormOperation) -> bool,
2504{
2505 for form in forms {
2506 if let DefaultedFormOperations::Custom(ops) = &form.op {
2507 let invalid_op = ops.iter().copied().find(|&op| is_allowed_op(op).not());
2508 if let Some(operation) = invalid_op {
2509 return Err(Error::InvalidOpInForm {
2510 context: affordance_type.into(),
2511 operation,
2512 });
2513 }
2514 }
2515
2516 form.security
2517 .as_ref()
2518 .map(|securities| {
2519 securities.iter().try_for_each(|security| {
2520 if security_definitions.contains_key(security) {
2521 Ok(())
2522 } else {
2523 Err(Error::UndefinedSecurity(security.clone()))
2524 }
2525 })
2526 })
2527 .transpose()?;
2528 }
2529
2530 Ok(())
2531}
2532
2533pub(crate) struct UncheckedInteractionAffordance<Other: ExtendableThing> {
2534 attype: Option<Vec<String>>,
2535 title: Option<String>,
2536 titles: Option<MultiLanguageBuilder<String>>,
2537 description: Option<String>,
2538 descriptions: Option<MultiLanguageBuilder<String>>,
2539 forms: Vec<Form<Other>>,
2540 uri_variables: Option<UncheckedDataSchemaMap<Other>>,
2541 other: Other::InteractionAffordance,
2542}
2543
2544impl<Other: ExtendableThing, OtherInteractionAffordance>
2545 TryFrom<InteractionAffordanceBuilder<Other, OtherInteractionAffordance>>
2546 for InteractionAffordance<Other>
2547where
2548 Other: ExtendableThing,
2549 OtherInteractionAffordance: Into<Other::InteractionAffordance>,
2550{
2551 type Error = Error;
2552
2553 fn try_from(
2554 builder: InteractionAffordanceBuilder<Other, OtherInteractionAffordance>,
2555 ) -> Result<Self, Self::Error> {
2556 let interaction: UncheckedInteractionAffordance<_> = builder.into();
2557 interaction.try_into()
2558 }
2559}
2560
2561impl<Other: ExtendableThing> TryFrom<UncheckedInteractionAffordance<Other>>
2562 for InteractionAffordance<Other>
2563{
2564 type Error = Error;
2565
2566 fn try_from(affordance: UncheckedInteractionAffordance<Other>) -> Result<Self, Self::Error> {
2567 let UncheckedInteractionAffordance {
2568 attype,
2569 title,
2570 titles,
2571 description,
2572 descriptions,
2573 forms,
2574 uri_variables,
2575 other,
2576 } = affordance;
2577
2578 let titles = titles.map(|titles| titles.build()).transpose()?;
2579 let descriptions = descriptions
2580 .map(|descriptions| descriptions.build())
2581 .transpose()?;
2582 let uri_variables = uri_variables
2583 .map(|uri_variables| {
2584 uri_variables
2585 .into_iter()
2586 .map(|(key, value)| value.try_into().map(|value| (key, value)))
2587 .collect()
2588 })
2589 .transpose()?;
2590
2591 Ok(Self {
2592 attype,
2593 title,
2594 titles,
2595 description,
2596 descriptions,
2597 forms,
2598 uri_variables,
2599 other,
2600 })
2601 }
2602}
2603
2604pub(crate) trait BuildableAffordance {
2605 type Target;
2606
2607 fn build(self) -> Result<Self::Target, Error>;
2608}
2609
2610impl<Other, DS, AS, OS> BuildableAffordance for UsablePropertyAffordanceBuilder<Other>
2611where
2612 Other: ExtendableThing<DataSchema = DS, ArraySchema = AS, ObjectSchema = OS>,
2613{
2614 type Target = PropertyAffordance<Other>;
2615
2616 fn build(self) -> Result<Self::Target, Error> {
2617 let Self {
2618 interaction,
2619 info,
2620 data_schema,
2621 observable,
2622 other,
2623 } = self;
2624
2625 let PartialInteractionAffordanceBuilder {
2626 forms,
2627 uri_variables,
2628 other: other_interaction,
2629 } = interaction;
2630
2631 let PartialDataSchema {
2632 constant,
2633 default,
2634 unit,
2635 one_of,
2636 enumeration,
2637 read_only,
2638 write_only,
2639 format,
2640 subtype,
2641 other: data_schema_other,
2642 } = data_schema;
2643
2644 let HumanReadableInfo {
2645 attype,
2646 title,
2647 titles,
2648 description,
2649 descriptions,
2650 } = info;
2651
2652 let titles = titles.map(|titles| titles.build()).transpose()?;
2653 let descriptions = descriptions
2654 .map(|descriptions| descriptions.build())
2655 .transpose()?;
2656 let forms = forms.into_iter().map(Into::into).collect();
2657 let uri_variables = uri_variables
2658 .is_empty()
2659 .not()
2660 .then(|| {
2661 uri_variables
2662 .into_iter()
2663 .map(|(key, value)| value.try_into().map(|value| (key, value)))
2664 .collect()
2665 })
2666 .transpose()?;
2667 let one_of = one_of
2668 .map(|one_of| one_of.into_iter().map(TryInto::try_into).collect())
2669 .transpose()?;
2670 let subtype = subtype.map(TryInto::try_into).transpose()?;
2671
2672 let interaction = InteractionAffordance {
2673 attype: attype.clone(),
2674 title: title.clone(),
2675 titles: titles.clone(),
2676 description: description.clone(),
2677 descriptions: descriptions.clone(),
2678 forms,
2679 uri_variables,
2680 other: other_interaction,
2681 };
2682
2683 let data_schema = DataSchema {
2684 attype,
2685 title,
2686 titles,
2687 description,
2688 descriptions,
2689 constant,
2690 default,
2691 unit,
2692 one_of,
2693 enumeration,
2694 read_only,
2695 write_only,
2696 format,
2697 subtype,
2698 other: data_schema_other,
2699 };
2700
2701 Ok(PropertyAffordance {
2702 interaction,
2703 data_schema,
2704 observable,
2705 other,
2706 })
2707 }
2708}
2709
2710impl<Other, OtherInteractionAffordance, OtherEventAffordance> BuildableAffordance
2711 for EventAffordanceBuilder<Other, OtherInteractionAffordance, OtherEventAffordance>
2712where
2713 Other: ExtendableThing,
2714 OtherInteractionAffordance: Into<Other::InteractionAffordance>,
2715 OtherEventAffordance: Into<Other::EventAffordance>,
2716{
2717 type Target = EventAffordance<Other>;
2718
2719 fn build(self) -> Result<Self::Target, Error> {
2720 let Self {
2721 interaction,
2722 subscription,
2723 data,
2724 cancellation,
2725 data_response,
2726 other,
2727 } = self;
2728
2729 let interaction = interaction.try_into()?;
2730 let subscription = subscription
2731 .map(|subscription| subscription.try_into())
2732 .transpose()?;
2733 let data = data.map(|data| data.try_into()).transpose()?;
2734 let cancellation = cancellation
2735 .map(|cancellation| cancellation.try_into())
2736 .transpose()?;
2737 let data_response = data_response
2738 .map(|data_response| data_response.try_into())
2739 .transpose()?;
2740 let other = other.into();
2741
2742 Ok(Self::Target {
2743 interaction,
2744 subscription,
2745 data,
2746 cancellation,
2747 data_response,
2748 other,
2749 })
2750 }
2751}
2752
2753impl<Other, OtherInteractionAffordance, OtherActionAffordance> BuildableAffordance
2754 for ActionAffordanceBuilder<Other, OtherInteractionAffordance, OtherActionAffordance>
2755where
2756 Other: ExtendableThing,
2757 OtherInteractionAffordance: Into<Other::InteractionAffordance>,
2758 OtherActionAffordance: Into<Other::ActionAffordance>,
2759{
2760 type Target = ActionAffordance<Other>;
2761
2762 fn build(self) -> Result<Self::Target, Error> {
2763 let Self {
2764 interaction,
2765 input,
2766 output,
2767 safe,
2768 idempotent,
2769 synchronous,
2770 other,
2771 } = self;
2772
2773 let interaction = interaction.try_into()?;
2774 let input = input.map(|input| input.try_into()).transpose()?;
2775 let output = output.map(|output| output.try_into()).transpose()?;
2776 let other = other.into();
2777
2778 Ok(Self::Target {
2779 interaction,
2780 input,
2781 output,
2782 safe,
2783 idempotent,
2784 synchronous,
2785 other,
2786 })
2787 }
2788}
2789
2790#[cfg(test)]
2791mod test {
2792 use alloc::{borrow::ToOwned, boxed::Box, string::*, vec};
2793
2794 use serde::{Deserialize, Serialize};
2795 use serde_json::json;
2796
2797 use crate::{
2798 builder::data_schema::{
2799 BuildableDataSchema, NumberDataSchemaBuilderLike, PartialDataSchemaBuilder,
2800 },
2801 hlist::{Cons, Nil},
2802 thing::{
2803 ArraySchema, BoxedElemOrVec, DataSchemaFromOther, DataSchemaSubtype,
2804 DefaultedFormOperations, FormOperation, Minimum, NumberSchema,
2805 },
2806 };
2807
2808 use super::*;
2809
2810 #[test]
2811 fn empty_iteraction() {
2812 let affordance: UncheckedInteractionAffordance<Nil> =
2813 InteractionAffordanceBuilder::<Nil, ()>::default().into();
2814 let affordance: InteractionAffordance<_> = affordance.try_into().unwrap();
2815 assert_eq!(affordance, InteractionAffordance::default());
2816 }
2817
2818 #[test]
2819 fn full_interaction() {
2820 let affordance: UncheckedInteractionAffordance<Nil> =
2821 InteractionAffordanceBuilder::<Nil, ()>::default()
2822 .attype("attype1")
2823 .attype("attype2")
2824 .title("title")
2825 .titles(|b| b.add("it", "title_it").add("en", "title_en"))
2826 .description("description")
2827 .descriptions(|b| b.add("it", "description_it").add("en", "description_en"))
2828 .form(|b| b.href("form1_href").content_type("content_type"))
2829 .form(|b| {
2830 b.op(FormOperation::WriteProperty)
2831 .op(FormOperation::ReadProperty)
2832 .href("form2_href")
2833 })
2834 .uri_variable("uri1", |b| b.finish_extend().number())
2835 .uri_variable("uri2", |b| b.finish_extend().integer())
2836 .into();
2837 let affordance: InteractionAffordance<Nil> = affordance.try_into().unwrap();
2838
2839 assert_eq!(
2840 affordance,
2841 InteractionAffordance {
2842 attype: Some(vec!["attype1".to_string(), "attype2".to_string()]),
2843 title: Some("title".to_string()),
2844 titles: Some(
2845 [("it", "title_it"), ("en", "title_en"),]
2846 .into_iter()
2847 .map(|(k, v)| (k.parse().unwrap(), v.to_string()))
2848 .collect()
2849 ),
2850 description: Some("description".to_string()),
2851 descriptions: Some(
2852 [("it", "description_it"), ("en", "description_en"),]
2853 .into_iter()
2854 .map(|(k, v)| (k.parse().unwrap(), v.to_string()))
2855 .collect()
2856 ),
2857 forms: vec![
2858 Form {
2859 op: DefaultedFormOperations::Default,
2860 href: "form1_href".to_string(),
2861 content_type: Some("content_type".to_string()),
2862 ..Default::default()
2863 },
2864 Form {
2865 op: DefaultedFormOperations::Custom(vec![
2866 FormOperation::WriteProperty,
2867 FormOperation::ReadProperty,
2868 ]),
2869 href: "form2_href".to_string(),
2870 ..Default::default()
2871 },
2872 ],
2873 uri_variables: Some(
2874 [
2875 (
2876 "uri1".to_string(),
2877 DataSchema {
2878 subtype: Some(DataSchemaSubtype::Number(Default::default())),
2879 ..Default::default()
2880 },
2881 ),
2882 (
2883 "uri2".to_string(),
2884 DataSchema {
2885 subtype: Some(DataSchemaSubtype::Integer(Default::default())),
2886 ..Default::default()
2887 },
2888 ),
2889 ]
2890 .into_iter()
2891 .collect()
2892 ),
2893 other: Default::default(),
2894 },
2895 );
2896 }
2897
2898 #[test]
2899 fn property_basic() {
2900 let affordance_builder: UsablePropertyAffordanceBuilder<Nil> = PropertyAffordanceBuilder::<
2901 Nil,
2902 PartialDataSchemaBuilder<_, _, _, _>,
2903 (),
2904 (),
2905 >::default()
2906 .title("property")
2907 .default_value(["hello", "world"].as_slice())
2908 .number()
2909 .observable(true)
2910 .form(|b| b.href("href"))
2911 .unit("cm")
2912 .read_only()
2913 .minimum(0.)
2914 .uri_variable("test", |b| b.finish_extend().bool())
2915 .into_usable();
2916
2917 let affordance: PropertyAffordance<Nil> = affordance_builder.build().unwrap();
2918
2919 assert_eq!(
2920 affordance,
2921 PropertyAffordance {
2922 interaction: InteractionAffordance {
2923 title: Some("property".to_owned()),
2924 forms: vec![Form {
2925 href: "href".to_owned(),
2926 ..Default::default()
2927 }],
2928 uri_variables: Some(
2929 [(
2930 "test".to_owned(),
2931 DataSchemaFromOther::<Nil> {
2932 subtype: Some(DataSchemaSubtype::Boolean),
2933 ..Default::default()
2934 }
2935 )]
2936 .into_iter()
2937 .collect()
2938 ),
2939 ..Default::default()
2940 },
2941 data_schema: DataSchemaFromOther::<Nil> {
2942 title: Some("property".to_owned()),
2943 unit: Some("cm".to_owned()),
2944 default: Some(json! { ["hello", "world"] }),
2945 read_only: true,
2946 subtype: Some(DataSchemaSubtype::Number(NumberSchema {
2947 minimum: Some(Minimum::Inclusive(0.)),
2948 ..Default::default()
2949 })),
2950 ..Default::default()
2951 },
2952 observable: Some(true),
2953 other: Nil,
2954 },
2955 );
2956 }
2957
2958 #[test]
2959 fn property_enum() {
2960 let affordance_builder: UsablePropertyAffordanceBuilder<Nil> = PropertyAffordanceBuilder::<
2961 Nil,
2962 PartialDataSchemaBuilder<_, _, _, _>,
2963 (),
2964 (),
2965 >::default()
2966 .title("property")
2967 .enumeration("enum1")
2968 .write_only()
2969 .enumeration("enum2")
2970 .observable(true)
2971 .form(|b| b.href("href"))
2972 .unit("cm")
2973 .into_usable();
2974
2975 let affordance: PropertyAffordance<Nil> = affordance_builder.build().unwrap();
2976
2977 assert_eq!(
2978 affordance,
2979 PropertyAffordance {
2980 interaction: InteractionAffordance {
2981 title: Some("property".to_owned()),
2982 forms: vec![Form {
2983 href: "href".to_owned(),
2984 ..Default::default()
2985 }],
2986 ..Default::default()
2987 },
2988 data_schema: DataSchemaFromOther::<Nil> {
2989 title: Some("property".to_owned()),
2990 unit: Some("cm".to_owned()),
2991 enumeration: Some(vec!["enum1".into(), "enum2".into()]),
2992 write_only: true,
2993 ..Default::default()
2994 },
2995 observable: Some(true),
2996 other: Nil,
2997 },
2998 );
2999 }
3000
3001 #[test]
3002 fn property_one_of() {
3003 let affordance_builder: UsablePropertyAffordanceBuilder<Nil> = PropertyAffordanceBuilder::<
3004 Nil,
3005 PartialDataSchemaBuilder<_, _, _, _>,
3006 (),
3007 (),
3008 >::default()
3009 .title("property")
3010 .one_of(|b| b.finish_extend().number())
3011 .one_of(|b| b.finish_extend().integer())
3012 .observable(true)
3013 .form(|b| b.href("href"))
3014 .unit("cm")
3015 .into_usable();
3016
3017 let affordance: PropertyAffordance<Nil> = affordance_builder.build().unwrap();
3018
3019 assert_eq!(
3020 affordance,
3021 PropertyAffordance {
3022 interaction: InteractionAffordance {
3023 title: Some("property".to_owned()),
3024 forms: vec![Form {
3025 href: "href".to_owned(),
3026 ..Default::default()
3027 }],
3028 ..Default::default()
3029 },
3030 data_schema: DataSchemaFromOther::<Nil> {
3031 title: Some("property".to_owned()),
3032 unit: Some("cm".to_owned()),
3033 one_of: Some(vec![
3034 DataSchemaFromOther::<Nil> {
3035 subtype: Some(DataSchemaSubtype::Number(Default::default())),
3036 ..Default::default()
3037 },
3038 DataSchemaFromOther::<Nil> {
3039 subtype: Some(DataSchemaSubtype::Integer(Default::default())),
3040 ..Default::default()
3041 },
3042 ]),
3043 ..Default::default()
3044 },
3045 observable: Some(true),
3046 other: Nil,
3047 },
3048 );
3049 }
3050
3051 #[test]
3052 fn action_partial() {
3053 let affordance_builder: UsableActionAffordanceBuilder<Nil> =
3054 ActionAffordanceBuilder::<Nil, (), ()>::default()
3055 .title("action")
3056 .safe()
3057 .input(|b| {
3058 b.finish_extend()
3059 .number()
3060 .unit("cm")
3061 .read_only()
3062 .minimum(0.)
3063 })
3064 .form(|b| b.href("href"))
3065 .into_usable();
3066
3067 let affordance: ActionAffordance<Nil> = affordance_builder.build().unwrap();
3068
3069 assert_eq!(
3070 affordance,
3071 ActionAffordance {
3072 interaction: InteractionAffordance {
3073 title: Some("action".to_owned()),
3074 forms: vec![Form {
3075 href: "href".to_owned(),
3076 ..Default::default()
3077 }],
3078 ..Default::default()
3079 },
3080 input: Some(DataSchemaFromOther::<Nil> {
3081 unit: Some("cm".to_owned()),
3082 read_only: true,
3083 subtype: Some(DataSchemaSubtype::Number(NumberSchema {
3084 minimum: Some(Minimum::Inclusive(0.)),
3085 ..Default::default()
3086 })),
3087 ..Default::default()
3088 }),
3089 safe: true,
3090 ..Default::default()
3091 },
3092 );
3093 }
3094
3095 #[test]
3096 fn action_full() {
3097 let affordance_builder: UsableActionAffordanceBuilder<Nil> =
3098 ActionAffordanceBuilder::<Nil, (), ()>::default()
3099 .title("action")
3100 .safe()
3101 .input(|b| {
3102 b.finish_extend()
3103 .number()
3104 .unit("cm")
3105 .read_only()
3106 .minimum(0.)
3107 })
3108 .idempotent()
3109 .output(|b| {
3110 b.finish_extend()
3111 .number()
3112 .unit("cm")
3113 .read_only()
3114 .minimum(0.)
3115 })
3116 .form(|b| b.href("href"))
3117 .synchronous(true)
3118 .into_usable();
3119
3120 let affordance: ActionAffordance<Nil> = affordance_builder.build().unwrap();
3121
3122 assert_eq!(
3123 affordance,
3124 ActionAffordance {
3125 interaction: InteractionAffordance {
3126 title: Some("action".to_owned()),
3127 forms: vec![Form {
3128 href: "href".to_owned(),
3129 ..Default::default()
3130 }],
3131 ..Default::default()
3132 },
3133 input: Some(DataSchemaFromOther::<Nil> {
3134 unit: Some("cm".to_owned()),
3135 read_only: true,
3136 subtype: Some(DataSchemaSubtype::Number(NumberSchema {
3137 minimum: Some(Minimum::Inclusive(0.)),
3138 ..Default::default()
3139 })),
3140 ..Default::default()
3141 }),
3142 output: Some(DataSchemaFromOther::<Nil> {
3143 unit: Some("cm".to_owned()),
3144 read_only: true,
3145 subtype: Some(DataSchemaSubtype::Number(NumberSchema {
3146 minimum: Some(Minimum::Inclusive(0.)),
3147 ..Default::default()
3148 })),
3149 ..Default::default()
3150 }),
3151 safe: true,
3152 idempotent: true,
3153 synchronous: Some(true),
3154 other: Nil,
3155 },
3156 );
3157 }
3158
3159 #[test]
3160 fn event_partial() {
3161 let affordance_builder: UsableEventAffordanceBuilder<Nil> =
3162 EventAffordanceBuilder::<Nil, (), ()>::default()
3163 .title("event")
3164 .data(|b| {
3165 b.finish_extend()
3166 .number()
3167 .unit("cm")
3168 .read_only()
3169 .minimum(0.)
3170 })
3171 .form(|b| b.href("href"))
3172 .into_usable();
3173
3174 let affordance: EventAffordance<Nil> = affordance_builder.build().unwrap();
3175
3176 assert_eq!(
3177 affordance,
3178 EventAffordance {
3179 interaction: InteractionAffordance {
3180 title: Some("event".to_owned()),
3181 forms: vec![Form {
3182 href: "href".to_owned(),
3183 ..Default::default()
3184 }],
3185 ..Default::default()
3186 },
3187 data: Some(DataSchemaFromOther::<Nil> {
3188 unit: Some("cm".to_owned()),
3189 read_only: true,
3190 subtype: Some(DataSchemaSubtype::Number(NumberSchema {
3191 minimum: Some(Minimum::Inclusive(0.)),
3192 ..Default::default()
3193 })),
3194 ..Default::default()
3195 }),
3196 ..Default::default()
3197 },
3198 );
3199 }
3200
3201 #[test]
3202 fn event_full() {
3203 let affordance_builder: UsableEventAffordanceBuilder<Nil> =
3204 EventAffordanceBuilder::<Nil, (), ()>::default()
3205 .title("event")
3206 .cancellation(|b| b.finish_extend().integer())
3207 .data(|b| {
3208 b.finish_extend()
3209 .number()
3210 .unit("cm")
3211 .read_only()
3212 .minimum(0.)
3213 })
3214 .subscription(|b| b.finish_extend().bool())
3215 .data_response(|b| b.finish_extend().string())
3216 .form(|b| b.href("href"))
3217 .into_usable();
3218
3219 let affordance: EventAffordance<Nil> = affordance_builder.build().unwrap();
3220
3221 assert_eq!(
3222 affordance,
3223 EventAffordance {
3224 interaction: InteractionAffordance {
3225 title: Some("event".to_owned()),
3226 forms: vec![Form {
3227 href: "href".to_owned(),
3228 ..Default::default()
3229 }],
3230 ..Default::default()
3231 },
3232 subscription: Some(DataSchemaFromOther::<Nil> {
3233 subtype: Some(DataSchemaSubtype::Boolean),
3234 ..Default::default()
3235 }),
3236 data: Some(DataSchemaFromOther::<Nil> {
3237 unit: Some("cm".to_owned()),
3238 read_only: true,
3239 subtype: Some(DataSchemaSubtype::Number(NumberSchema {
3240 minimum: Some(Minimum::Inclusive(0.)),
3241 ..Default::default()
3242 })),
3243 ..Default::default()
3244 }),
3245 cancellation: Some(DataSchemaFromOther::<Nil> {
3246 subtype: Some(DataSchemaSubtype::Integer(Default::default())),
3247 ..Default::default()
3248 }),
3249 data_response: Some(DataSchemaFromOther::<Nil> {
3250 subtype: Some(DataSchemaSubtype::String(Default::default())),
3251 ..Default::default()
3252 }),
3253 other: Nil,
3254 },
3255 );
3256 }
3257
3258 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3259 struct A(i32);
3260 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3261 struct B(String);
3262
3263 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3264 struct ThingExtA {}
3265
3266 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3267 struct InteractionAffordanceExtA {
3268 a: A,
3269 }
3270
3271 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3272 struct PropertyAffordanceExtA {
3273 b: A,
3274 }
3275
3276 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3277 struct ActionAffordanceExtA {
3278 b: A,
3279 }
3280
3281 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3282 struct EventAffordanceExtA {
3283 c: A,
3284 }
3285
3286 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3287 struct FormExtA {
3288 d: A,
3289 }
3290
3291 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3292 struct ExpectedResponseExtA {
3293 e: A,
3294 }
3295
3296 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3297 struct DataSchemaExtA {
3298 f: A,
3299 }
3300
3301 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3302 struct ThingExtB {}
3303
3304 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3305 struct InteractionAffordanceExtB {
3306 g: B,
3307 }
3308
3309 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3310 struct PropertyAffordanceExtB {
3311 h: B,
3312 }
3313
3314 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3315 struct ActionAffordanceExtB {
3316 i: B,
3317 }
3318
3319 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3320 struct EventAffordanceExtB {
3321 j: B,
3322 }
3323
3324 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3325 struct FormExtB {
3326 k: B,
3327 }
3328
3329 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3330 struct ExpectedResponseExtB {
3331 l: B,
3332 }
3333
3334 #[derive(Debug, PartialEq, Serialize, Deserialize)]
3335 struct DataSchemaExtB {
3336 m: B,
3337 }
3338
3339 impl ExtendableThing for ThingExtA {
3340 type InteractionAffordance = InteractionAffordanceExtA;
3341 type PropertyAffordance = PropertyAffordanceExtA;
3342 type ActionAffordance = ActionAffordanceExtA;
3343 type EventAffordance = EventAffordanceExtA;
3344 type Form = FormExtA;
3345 type ExpectedResponse = ExpectedResponseExtA;
3346 type DataSchema = DataSchemaExtA;
3347 type ObjectSchema = ();
3348 type ArraySchema = ();
3349 }
3350
3351 impl ExtendableThing for ThingExtB {
3352 type InteractionAffordance = InteractionAffordanceExtB;
3353 type PropertyAffordance = PropertyAffordanceExtB;
3354 type ActionAffordance = ActionAffordanceExtB;
3355 type EventAffordance = EventAffordanceExtB;
3356 type Form = FormExtB;
3357 type ExpectedResponse = ExpectedResponseExtB;
3358 type DataSchema = DataSchemaExtB;
3359 type ObjectSchema = ();
3360 type ArraySchema = ();
3361 }
3362
3363 #[test]
3364 fn extend_interaction() {
3365 let affordance: UncheckedInteractionAffordance<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
3366 InteractionAffordanceBuilder::<Cons<ThingExtB, Cons<ThingExtA, Nil>>, _>::empty()
3367 .title("title")
3368 .ext(InteractionAffordanceExtA { a: A(1) })
3369 .uri_variable("x", |b| {
3370 b.ext(DataSchemaExtA { f: A(2) })
3371 .ext_with(|| DataSchemaExtB {
3372 m: B("a".to_string()),
3373 })
3374 .finish_extend()
3375 .null()
3376 })
3377 .ext_with(|| InteractionAffordanceExtB {
3378 g: B("b".to_string()),
3379 })
3380 .form(|b| {
3381 b.ext(FormExtA { d: A(3) })
3382 .ext(FormExtB {
3383 k: B("c".to_string()),
3384 })
3385 .href("href")
3386 })
3387 .into();
3388 let affordance: InteractionAffordance<_> = affordance.try_into().unwrap();
3389
3390 assert_eq!(
3391 affordance,
3392 InteractionAffordance {
3393 title: Some("title".to_string()),
3394 uri_variables: Some(
3395 [(
3396 "x".to_string(),
3397 DataSchema {
3398 subtype: Some(DataSchemaSubtype::Null),
3399 other: Nil::cons(DataSchemaExtA { f: A(2) }).cons(DataSchemaExtB {
3400 m: B("a".to_string())
3401 }),
3402 attype: Default::default(),
3403 title: Default::default(),
3404 titles: Default::default(),
3405 description: Default::default(),
3406 descriptions: Default::default(),
3407 constant: Default::default(),
3408 default: Default::default(),
3409 unit: Default::default(),
3410 one_of: Default::default(),
3411 enumeration: Default::default(),
3412 read_only: Default::default(),
3413 write_only: Default::default(),
3414 format: Default::default(),
3415 }
3416 )]
3417 .into_iter()
3418 .collect()
3419 ),
3420 forms: vec![Form {
3421 href: "href".to_string(),
3422 other: Nil::cons(FormExtA { d: A(3) }).cons(FormExtB {
3423 k: B("c".to_string())
3424 }),
3425 op: Default::default(),
3426 content_type: Default::default(),
3427 content_coding: Default::default(),
3428 subprotocol: Default::default(),
3429 security: Default::default(),
3430 scopes: Default::default(),
3431 response: Default::default(),
3432 additional_responses: Default::default(),
3433 }],
3434 other: Nil::cons(InteractionAffordanceExtA { a: A(1) }).cons(
3435 InteractionAffordanceExtB {
3436 g: B("b".to_string())
3437 }
3438 ),
3439 attype: Default::default(),
3440 titles: Default::default(),
3441 description: Default::default(),
3442 descriptions: Default::default(),
3443 },
3444 );
3445 }
3446
3447 #[test]
3448 fn extend_property() {
3449 let builder: UsablePropertyAffordanceBuilder<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
3450 PropertyAffordanceBuilder::<Cons<ThingExtB, Cons<ThingExtA, Nil>>, _, _, _>::empty()
3451 .ext(PropertyAffordanceExtA { b: A(1) })
3452 .title("title")
3453 .ext_interaction(InteractionAffordanceExtA { a: A(2) })
3454 .ext_data_schema(DataSchemaExtA { f: A(4) })
3455 .uri_variable("x", |b| {
3456 b.ext(DataSchemaExtA { f: A(3) })
3457 .ext_with(|| DataSchemaExtB {
3458 m: B("a".to_string()),
3459 })
3460 .finish_extend()
3461 .null()
3462 })
3463 .ext_data_schema_with(|| DataSchemaExtB {
3464 m: B("d".to_string()),
3465 })
3466 .ext_interaction_with(|| InteractionAffordanceExtB {
3467 g: B("b".to_string()),
3468 })
3469 .finish_extend_data_schema()
3470 .ext_with(|| PropertyAffordanceExtB {
3471 h: B("c".to_string()),
3472 })
3473 .null()
3474 .into_usable();
3475 let affordance: PropertyAffordance<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
3476 builder.build().unwrap();
3477
3478 assert_eq!(
3479 affordance,
3480 PropertyAffordance {
3481 interaction: InteractionAffordance {
3482 other: Nil::cons(InteractionAffordanceExtA { a: A(2) }).cons(
3483 InteractionAffordanceExtB {
3484 g: B("b".to_string())
3485 }
3486 ),
3487 uri_variables: Some(
3488 [(
3489 "x".to_string(),
3490 DataSchema {
3491 subtype: Some(DataSchemaSubtype::Null),
3492 other: Nil::cons(DataSchemaExtA { f: A(3) }).cons(DataSchemaExtB {
3493 m: B("a".to_string())
3494 }),
3495 attype: Default::default(),
3496 title: Default::default(),
3497 titles: Default::default(),
3498 description: Default::default(),
3499 descriptions: Default::default(),
3500 constant: Default::default(),
3501 default: Default::default(),
3502 unit: Default::default(),
3503 one_of: Default::default(),
3504 enumeration: Default::default(),
3505 read_only: Default::default(),
3506 write_only: Default::default(),
3507 format: Default::default(),
3508 }
3509 )]
3510 .into_iter()
3511 .collect()
3512 ),
3513 attype: Default::default(),
3514 title: Some("title".to_string()),
3515 titles: Default::default(),
3516 description: Default::default(),
3517 descriptions: Default::default(),
3518 forms: Default::default(),
3519 },
3520 data_schema: DataSchema {
3521 title: Some("title".to_string()),
3522 subtype: Some(DataSchemaSubtype::Null),
3523 other: Nil::cons(DataSchemaExtA { f: A(4) }).cons(DataSchemaExtB {
3524 m: B("d".to_string())
3525 }),
3526 attype: Default::default(),
3527 titles: Default::default(),
3528 description: Default::default(),
3529 descriptions: Default::default(),
3530 constant: Default::default(),
3531 default: Default::default(),
3532 unit: Default::default(),
3533 one_of: Default::default(),
3534 enumeration: Default::default(),
3535 read_only: Default::default(),
3536 write_only: Default::default(),
3537 format: Default::default(),
3538 },
3539 other: Nil::cons(PropertyAffordanceExtA { b: A(1) }).cons(PropertyAffordanceExtB {
3540 h: B("c".to_string())
3541 }),
3542 observable: Default::default(),
3543 }
3544 );
3545 }
3546
3547 #[test]
3548 fn extend_event() {
3549 let builder: UsableEventAffordanceBuilder<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
3550 EventAffordanceBuilder::<Cons<ThingExtB, Cons<ThingExtA, Nil>>, _, _>::empty()
3551 .title("title")
3552 .ext_interaction(InteractionAffordanceExtA { a: A(1) })
3553 .uri_variable("x", |b| {
3554 b.ext(DataSchemaExtA { f: A(2) })
3555 .ext_with(|| DataSchemaExtB {
3556 m: B("a".to_string()),
3557 })
3558 .finish_extend()
3559 .null()
3560 })
3561 .ext_interaction_with(|| InteractionAffordanceExtB {
3562 g: B("b".to_string()),
3563 })
3564 .ext(EventAffordanceExtA { c: A(3) })
3565 .ext_with(|| EventAffordanceExtB {
3566 j: B("c".to_string()),
3567 })
3568 .subscription(|b| {
3569 b.ext(DataSchemaExtA { f: A(4) })
3570 .ext_with(|| DataSchemaExtB {
3571 m: B("d".to_string()),
3572 })
3573 .finish_extend()
3574 .null()
3575 })
3576 .into_usable();
3577 let affordance: EventAffordance<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
3578 builder.build().unwrap();
3579
3580 assert_eq!(
3581 affordance,
3582 EventAffordance {
3583 interaction: InteractionAffordance {
3584 title: Some("title".to_string()),
3585 uri_variables: Some(
3586 [(
3587 "x".to_string(),
3588 DataSchema {
3589 subtype: Some(DataSchemaSubtype::Null),
3590 other: Nil::cons(DataSchemaExtA { f: A(2) }).cons(DataSchemaExtB {
3591 m: B("a".to_string())
3592 }),
3593 attype: Default::default(),
3594 title: Default::default(),
3595 titles: Default::default(),
3596 description: Default::default(),
3597 descriptions: Default::default(),
3598 constant: Default::default(),
3599 default: Default::default(),
3600 unit: Default::default(),
3601 one_of: Default::default(),
3602 enumeration: Default::default(),
3603 read_only: Default::default(),
3604 write_only: Default::default(),
3605 format: Default::default(),
3606 }
3607 )]
3608 .into_iter()
3609 .collect()
3610 ),
3611 other: Nil::cons(InteractionAffordanceExtA { a: A(1) }).cons(
3612 InteractionAffordanceExtB {
3613 g: B("b".to_string())
3614 }
3615 ),
3616 attype: Default::default(),
3617 titles: Default::default(),
3618 description: Default::default(),
3619 descriptions: Default::default(),
3620 forms: Default::default(),
3621 },
3622 subscription: Some(DataSchema {
3623 subtype: Some(DataSchemaSubtype::Null),
3624 other: Nil::cons(DataSchemaExtA { f: A(4) }).cons(DataSchemaExtB {
3625 m: B("d".to_string())
3626 }),
3627 attype: Default::default(),
3628 title: Default::default(),
3629 titles: Default::default(),
3630 description: Default::default(),
3631 descriptions: Default::default(),
3632 constant: Default::default(),
3633 default: Default::default(),
3634 unit: Default::default(),
3635 one_of: Default::default(),
3636 enumeration: Default::default(),
3637 read_only: Default::default(),
3638 write_only: Default::default(),
3639 format: Default::default(),
3640 }),
3641 other: Nil::cons(EventAffordanceExtA { c: A(3) }).cons(EventAffordanceExtB {
3642 j: B("c".to_string())
3643 }),
3644 data: Default::default(),
3645 data_response: Default::default(),
3646 cancellation: Default::default(),
3647 },
3648 );
3649 }
3650
3651 #[test]
3652 fn extend_action() {
3653 let builder: UsableActionAffordanceBuilder<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
3654 ActionAffordanceBuilder::<Cons<ThingExtB, Cons<ThingExtA, Nil>>, _, _>::empty()
3655 .title("title")
3656 .ext_interaction(InteractionAffordanceExtA { a: A(1) })
3657 .uri_variable("x", |b| {
3658 b.ext(DataSchemaExtA { f: A(2) })
3659 .ext_with(|| DataSchemaExtB {
3660 m: B("a".to_string()),
3661 })
3662 .finish_extend()
3663 .null()
3664 })
3665 .ext_interaction_with(|| InteractionAffordanceExtB {
3666 g: B("b".to_string()),
3667 })
3668 .ext(ActionAffordanceExtA { b: A(3) })
3669 .ext_with(|| ActionAffordanceExtB {
3670 i: B("c".to_string()),
3671 })
3672 .input(|b| {
3673 b.ext(DataSchemaExtA { f: A(4) })
3674 .ext_with(|| DataSchemaExtB {
3675 m: B("d".to_string()),
3676 })
3677 .finish_extend()
3678 .null()
3679 })
3680 .into_usable();
3681 let affordance: ActionAffordance<Cons<ThingExtB, Cons<ThingExtA, Nil>>> =
3682 builder.build().unwrap();
3683
3684 assert_eq!(
3685 affordance,
3686 ActionAffordance {
3687 interaction: InteractionAffordance {
3688 title: Some("title".to_string()),
3689 uri_variables: Some(
3690 [(
3691 "x".to_string(),
3692 DataSchema {
3693 subtype: Some(DataSchemaSubtype::Null),
3694 other: Nil::cons(DataSchemaExtA { f: A(2) }).cons(DataSchemaExtB {
3695 m: B("a".to_string())
3696 }),
3697 attype: Default::default(),
3698 title: Default::default(),
3699 titles: Default::default(),
3700 description: Default::default(),
3701 descriptions: Default::default(),
3702 constant: Default::default(),
3703 default: Default::default(),
3704 unit: Default::default(),
3705 one_of: Default::default(),
3706 enumeration: Default::default(),
3707 read_only: Default::default(),
3708 write_only: Default::default(),
3709 format: Default::default(),
3710 }
3711 )]
3712 .into_iter()
3713 .collect()
3714 ),
3715 other: Nil::cons(InteractionAffordanceExtA { a: A(1) }).cons(
3716 InteractionAffordanceExtB {
3717 g: B("b".to_string())
3718 }
3719 ),
3720 attype: Default::default(),
3721 titles: Default::default(),
3722 description: Default::default(),
3723 descriptions: Default::default(),
3724 forms: Default::default(),
3725 },
3726 input: Some(DataSchema {
3727 subtype: Some(DataSchemaSubtype::Null),
3728 other: Nil::cons(DataSchemaExtA { f: A(4) }).cons(DataSchemaExtB {
3729 m: B("d".to_string())
3730 }),
3731 attype: Default::default(),
3732 title: Default::default(),
3733 titles: Default::default(),
3734 description: Default::default(),
3735 descriptions: Default::default(),
3736 constant: Default::default(),
3737 default: Default::default(),
3738 unit: Default::default(),
3739 one_of: Default::default(),
3740 enumeration: Default::default(),
3741 read_only: Default::default(),
3742 write_only: Default::default(),
3743 format: Default::default(),
3744 }),
3745 other: Nil::cons(ActionAffordanceExtA { b: A(3) }).cons(ActionAffordanceExtB {
3746 i: B("c".to_string())
3747 }),
3748 output: Default::default(),
3749 safe: Default::default(),
3750 idempotent: Default::default(),
3751 synchronous: Default::default(),
3752 },
3753 );
3754 }
3755
3756 #[test]
3757 fn build_invalid_property_affordance() {
3758 let builder = PropertyAffordanceBuilder::<
3759 Nil,
3760 PartialDataSchemaBuilder<_, _, _, _>,
3761 (),
3762 (),
3763 >::default()
3764 .number()
3765 .titles(|b| b.add("i1t", "title1"))
3766 .into_usable();
3767
3768 assert_eq!(
3769 builder.build().unwrap_err(),
3770 Error::InvalidLanguageTag("i1t".to_string()),
3771 );
3772 }
3773
3774 #[test]
3775 fn build_invalid_action_affordance() {
3776 let builder = ActionAffordanceBuilder::<Nil, (), ()>::default()
3777 .titles(|b| b.add("i1t", "title1"))
3778 .into_usable();
3779
3780 assert_eq!(
3781 builder.build().unwrap_err(),
3782 Error::InvalidLanguageTag("i1t".to_string()),
3783 );
3784 }
3785
3786 #[test]
3787 fn build_invalid_event_affordance() {
3788 let builder = EventAffordanceBuilder::<Nil, (), ()>::default()
3789 .titles(|b| b.add("i1t", "title1"))
3790 .into_usable();
3791
3792 assert_eq!(
3793 builder.build().unwrap_err(),
3794 Error::InvalidLanguageTag("i1t".to_string()),
3795 );
3796 }
3797
3798 #[test]
3799 fn delegate_vec_methods() {
3800 let builder = PropertyAffordanceBuilder::<Nil, PartialDataSchemaBuilder<_, _, _, _>, (), ()>::default()
3801 .vec()
3802 .read_only()
3803 .min_items(3)
3804 .max_items(5)
3805 .set_item(|b| b.finish_extend().integer())
3806 .into_usable();
3807
3808 assert_eq!(
3809 builder.build().unwrap(),
3810 PropertyAffordance {
3811 interaction: Default::default(),
3812 data_schema: DataSchema {
3813 read_only: true,
3814 subtype: Some(DataSchemaSubtype::Array(ArraySchema {
3815 items: Some(BoxedElemOrVec::Elem(Box::new(DataSchema {
3816 subtype: Some(DataSchemaSubtype::Integer(Default::default())),
3817 other: Nil,
3818 ..Default::default()
3819 }))),
3820 min_items: Some(3),
3821 max_items: Some(5),
3822 other: Nil,
3823 })),
3824 other: Nil,
3825 ..Default::default()
3826 },
3827 observable: Default::default(),
3828 other: Nil,
3829 }
3830 )
3831 }
3832
3833 #[test]
3834 fn delegate_tuple_methods() {
3835 let builder = PropertyAffordanceBuilder::<Nil, PartialDataSchemaBuilder<_, _, _, _>, (), ()>::default()
3836 .tuple()
3837 .read_only()
3838 .append(|b| b.finish_extend().integer())
3839 .append(|b| b.finish_extend().string())
3840 .into_usable();
3841
3842 assert_eq!(
3843 builder.build().unwrap(),
3844 PropertyAffordance {
3845 interaction: Default::default(),
3846 data_schema: DataSchema {
3847 read_only: true,
3848 subtype: Some(DataSchemaSubtype::Array(ArraySchema {
3849 items: Some(BoxedElemOrVec::Vec(vec![
3850 DataSchema {
3851 subtype: Some(DataSchemaSubtype::Integer(Default::default())),
3852 other: Nil,
3853 ..Default::default()
3854 },
3855 DataSchema {
3856 subtype: Some(DataSchemaSubtype::String(Default::default())),
3857 other: Nil,
3858 ..Default::default()
3859 },
3860 ])),
3861 min_items: None,
3862 max_items: None,
3863 other: Nil,
3864 })),
3865 other: Nil,
3866 ..Default::default()
3867 },
3868 observable: Default::default(),
3869 other: Nil,
3870 }
3871 )
3872 }
3873}