Skip to content

Commit 81acaf2

Browse files
authored
Merge pull request astarte-platform#442 from joshuachp/feature/new-api
feat(new-api): refactor the client and connection to follow the new SDK public API
2 parents 3b96ff3 + b38f02a commit 81acaf2

File tree

50 files changed

+3804
-3039
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3804
-3039
lines changed

astarte-device-sdk-derive/src/event.rs

Lines changed: 201 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub(crate) struct FromEventAttrs {
4141
rename_rule: Option<RenameRule>,
4242
// Use an option, so it can be merged if declared multiple times.
4343
aggregation: Option<Aggregation>,
44+
interface_type: Option<InterfaceType>,
4445
}
4546

4647
impl FromEventAttrs {
@@ -49,12 +50,14 @@ impl FromEventAttrs {
4950
let path = other.path.or(self.path);
5051
let rename_rule = other.rename_rule.or(self.rename_rule);
5152
let aggregation = other.aggregation.or(self.aggregation);
53+
let interface_type = other.interface_type.or(self.interface_type);
5254

5355
Self {
5456
interface,
5557
path,
5658
rename_rule,
5759
aggregation,
60+
interface_type,
5861
}
5962
}
6063
}
@@ -88,6 +91,11 @@ impl Parse for FromEventAttrs {
8891
.map(Aggregation::try_from)
8992
.transpose()?;
9093

94+
let interface_type = attrs
95+
.remove("interface_type")
96+
.map(InterfaceType::try_from)
97+
.transpose()?;
98+
9199
if let Some((_, expr)) = attrs.iter().next() {
92100
return Err(syn::Error::new(expr.span(), "unrecognized attribute"));
93101
}
@@ -97,14 +105,15 @@ impl Parse for FromEventAttrs {
97105
interface,
98106
path,
99107
aggregation,
108+
interface_type,
100109
})
101110
}
102111
}
103112

104113
#[derive(Debug, Default)]
105114
enum Aggregation {
106-
Individual,
107115
#[default]
116+
Individual,
108117
Object,
109118
}
110119

@@ -123,13 +132,35 @@ impl TryFrom<Expr> for Aggregation {
123132
}
124133
}
125134

135+
#[derive(Debug, Default)]
136+
enum InterfaceType {
137+
#[default]
138+
Datastream,
139+
Properties,
140+
}
141+
142+
impl TryFrom<Expr> for InterfaceType {
143+
type Error = syn::Error;
144+
145+
fn try_from(value: Expr) -> Result<Self, Self::Error> {
146+
parse_str_lit(&value).and_then(|val| match val.as_str() {
147+
"properties" => Ok(InterfaceType::Properties),
148+
"object" => Ok(InterfaceType::Datastream),
149+
_ => Err(syn::Error::new(
150+
value.span(),
151+
"invalid interface type, should be: property or datastream",
152+
)),
153+
})
154+
}
155+
}
156+
126157
/// Parses the derive for the FromEvent trait
127158
pub(crate) struct FromEventDerive {
128159
interface: String,
129160
name: Ident,
130161
rename_rule: Option<RenameRule>,
131162
generics: Generics,
132-
aggregation: FromEventAggregation,
163+
inner: FromEventAggregation,
133164
}
134165

135166
impl FromEventDerive {
@@ -145,9 +176,10 @@ impl FromEventDerive {
145176
}
146177

147178
pub(crate) fn quote(&self) -> proc_macro2::TokenStream {
148-
match &self.aggregation {
179+
match &self.inner {
149180
FromEventAggregation::Individual { variants } => self.quote_indv(variants),
150181
FromEventAggregation::Object { fields, path } => self.quote_obj(path, fields),
182+
FromEventAggregation::Property { variants } => self.quote_property(variants),
151183
}
152184
}
153185

@@ -178,6 +210,8 @@ impl FromEventDerive {
178210

179211
fn from_event(event: astarte_device_sdk::DeviceEvent) -> ::std::result::Result<Self, Self::Err> {
180212
use astarte_device_sdk::Value;
213+
use astarte_device_sdk::interface::def::{Aggregation, InterfaceTypeDef};
214+
use astarte_device_sdk::error::{AggregationError, InterfaceTypeError};
181215
use astarte_device_sdk::event::FromEventError;
182216
use astarte_device_sdk::interface::mapping::endpoint::Endpoint;
183217

@@ -196,11 +230,24 @@ impl FromEventDerive {
196230
});
197231
}
198232

199-
let Value::Object(mut object) = event.data else {
200-
return Err(FromEventError::Individual {
201-
interface,
202-
base_path,
203-
});
233+
let mut object = match event.data {
234+
Value::Object{data, ..} => data,
235+
Value::Individual{..} => {
236+
return Err(FromEventError::Aggregation(AggregationError::new(
237+
interface,
238+
event.path,
239+
Aggregation::Object,
240+
Aggregation::Individual,
241+
)));
242+
},
243+
Value::Property(_) => {
244+
return Err(FromEventError::InterfaceType(InterfaceTypeError::with_path(
245+
interface,
246+
event.path,
247+
InterfaceTypeDef::Datastream,
248+
InterfaceTypeDef::Properties,
249+
)));
250+
},
204251
};
205252

206253
#(#fields_val)*
@@ -227,50 +274,138 @@ impl FromEventDerive {
227274
}
228275
});
229276

277+
for variant in variants {
278+
if variant.attrs.allow_unset {
279+
return syn::Error::new(
280+
variant.name.span(),
281+
r#"the attribute allow_unset is only usable with `interface_type = "property"` on the container"#,
282+
)
283+
.to_compile_error();
284+
}
285+
}
286+
230287
let variants = variants.iter().enumerate().map(|(i, v)| {
231288
let variant = &v.name;
232289

233-
if v.attrs.allow_unset {
234-
quote! {
235-
#i => {
236-
let individual = match event.data {
237-
Value::Individual(individual) => individual,
238-
Value::Unset => {
239-
return Ok(#name::#variant(None));
240-
},
241-
Value::Object(_) => {
242-
return Err(FromEventError::Object {
243-
interface: INTERFACE,
244-
endpoint: event.path,
245-
});
246-
}
247-
};
248-
249-
individual.try_into()
250-
.map(|value| #name::#variant(Some(value)))
251-
.map_err(FromEventError::from)
290+
quote! {
291+
#i => {
292+
let individual = match event.data {
293+
Value::Individual{data, ..} => data,
294+
Value::Object{..} => {
295+
return Err(FromEventError::Aggregation(AggregationError::new(
296+
event.interface,
297+
event.path,
298+
Aggregation::Individual,
299+
Aggregation::Object,
300+
)));
301+
},
302+
Value::Property(_) => {
303+
return Err(FromEventError::InterfaceType(InterfaceTypeError::with_path(
304+
event.interface,
305+
event.path,
306+
InterfaceTypeDef::Datastream,
307+
InterfaceTypeDef::Properties,
308+
)));
309+
},
310+
};
311+
312+
313+
individual.try_into().map(#name::#variant).map_err(FromEventError::from)
314+
}
315+
}
316+
});
317+
318+
quote! {
319+
impl #impl_generics astarte_device_sdk::FromEvent for #name #ty_generics #where_clause {
320+
type Err = astarte_device_sdk::event::FromEventError;
321+
322+
fn from_event(event: astarte_device_sdk::DeviceEvent) -> ::std::result::Result<Self, Self::Err> {
323+
use astarte_device_sdk::Value;
324+
use astarte_device_sdk::AstarteType;
325+
use astarte_device_sdk::interface::def::{Aggregation, InterfaceTypeDef};
326+
use astarte_device_sdk::error::{AggregationError, InterfaceTypeError};
327+
use astarte_device_sdk::event::FromEventError;
328+
use astarte_device_sdk::interface::mapping::endpoint::Endpoint;
329+
330+
const INTERFACE: &str = #interface;
331+
332+
if event.interface != INTERFACE {
333+
return Err(FromEventError::Interface(event.interface));
334+
}
335+
336+
let endpoints = [ #(#endpoints),* ];
337+
338+
let position = endpoints.iter()
339+
.position(|e| e.eq_mapping(&event.path))
340+
.ok_or_else(|| FromEventError::Path {
341+
interface: INTERFACE,
342+
base_path: event.path.clone(),
343+
})?;
344+
345+
match position {
346+
#(#variants)*
347+
_ => unreachable!("BUG: endpoint found, but outside the range of the variants"),
252348
}
253349
}
350+
}
351+
}
352+
}
353+
354+
fn quote_property(&self, variants: &[IndividualMapping]) -> proc_macro2::TokenStream {
355+
let (impl_generics, ty_generics, where_clause) = &self.generics.split_for_impl();
356+
357+
let name = &self.name;
358+
let interface = self.interface.as_str();
359+
360+
// Use the same order between endpoints and variants, so we can find the correct endpoint
361+
// position and then match the index with the corresponding variant.
362+
let endpoints = variants.iter().map(|v| {
363+
let endpoint = v.attrs.endpoint.as_str();
364+
365+
quote! {
366+
Endpoint::<&str>::try_from(#endpoint)?
367+
}
368+
});
369+
370+
let variants = variants.iter().enumerate().map(|(i, v)| {
371+
let variant = &v.name;
372+
373+
let prop_set_case = if v.attrs.allow_unset {
374+
quote! { Some(value) }
375+
} else {
376+
quote! { value }
377+
};
378+
379+
let prop_unset = if v.attrs.allow_unset {
380+
quote! { Ok(#name::#variant(None)) }
254381
} else {
255382
quote! {
256-
#i => {
257-
let individual = match event.data {
258-
Value::Individual(individual) => individual,
259-
Value::Unset => {
260-
return Err(FromEventError::Unset {
261-
interface: INTERFACE,
262-
endpoint: event.path,
263-
});
264-
},
265-
Value::Object(_) => {
266-
return Err(FromEventError::Object {
267-
interface: INTERFACE,
268-
endpoint: event.path,
269-
});
270-
}
271-
};
272-
273-
individual.try_into().map(#name::#variant).map_err(FromEventError::from)
383+
return Err(FromEventError::Unset {
384+
interface: INTERFACE,
385+
endpoint: event.path,
386+
});
387+
}
388+
};
389+
390+
quote! {
391+
#i => {
392+
match event.data {
393+
Value::Individual{..} | Value::Object{..} => {
394+
return Err(FromEventError::InterfaceType(InterfaceTypeError::with_path(
395+
event.interface,
396+
event.path,
397+
InterfaceTypeDef::Properties,
398+
InterfaceTypeDef::Datastream,
399+
)));
400+
},
401+
Value::Property(Some(prop)) => {
402+
prop.try_into()
403+
.map(|value| #name::#variant(#prop_set_case))
404+
.map_err(FromEventError::from)
405+
},
406+
Value::Property(None) => {
407+
#prop_unset
408+
},
274409
}
275410
}
276411
}
@@ -283,6 +418,8 @@ impl FromEventDerive {
283418
fn from_event(event: astarte_device_sdk::DeviceEvent) -> ::std::result::Result<Self, Self::Err> {
284419
use astarte_device_sdk::Value;
285420
use astarte_device_sdk::AstarteType;
421+
use astarte_device_sdk::interface::def::{Aggregation, InterfaceTypeDef};
422+
use astarte_device_sdk::error::{AggregationError, InterfaceTypeError};
286423
use astarte_device_sdk::event::FromEventError;
287424
use astarte_device_sdk::interface::mapping::endpoint::Endpoint;
288425

@@ -337,13 +474,15 @@ impl Parse for FromEventDerive {
337474
)
338475
})?;
339476

340-
let aggregation = match attrs.aggregation.unwrap_or_default() {
341-
Aggregation::Individual => {
477+
let aggregation = attrs.aggregation.unwrap_or_default();
478+
let interface_type = attrs.interface_type.unwrap_or_default();
479+
let inner = match (aggregation, interface_type) {
480+
(Aggregation::Individual, InterfaceType::Datastream) => {
342481
let variants = FromEventAggregation::parse_enum_variants(&ast)?;
343482

344483
FromEventAggregation::Individual { variants }
345484
}
346-
Aggregation::Object => {
485+
(Aggregation::Object, InterfaceType::Datastream) => {
347486
let path = attrs.path.ok_or_else(|| {
348487
syn::Error::new(
349488
ast.span(),
@@ -355,6 +494,17 @@ impl Parse for FromEventDerive {
355494

356495
FromEventAggregation::Object { fields, path }
357496
}
497+
(Aggregation::Individual, InterfaceType::Properties) => {
498+
let variants = FromEventAggregation::parse_enum_variants(&ast)?;
499+
500+
FromEventAggregation::Property { variants }
501+
}
502+
(Aggregation::Object, InterfaceType::Properties) => {
503+
return Err(syn::Error::new(
504+
ast.span(),
505+
"object properties are not supported",
506+
));
507+
}
358508
};
359509

360510
let generics = Self::add_trait_bound(ast.generics);
@@ -364,14 +514,15 @@ impl Parse for FromEventDerive {
364514
rename_rule: attrs.rename_rule,
365515
name: ast.ident,
366516
generics,
367-
aggregation,
517+
inner,
368518
})
369519
}
370520
}
371521

372522
enum FromEventAggregation {
373523
Individual { variants: Vec<IndividualMapping> },
374524
Object { fields: Vec<Ident>, path: String },
525+
Property { variants: Vec<IndividualMapping> },
375526
}
376527

377528
impl FromEventAggregation {
@@ -443,7 +594,7 @@ struct MappingAttr {
443594
endpoint: String,
444595
/// Allow [`Option`]al values for properties.
445596
///
446-
/// Defaults to false as in the interfaces definition.
597+
/// Defaults to false as in the interfaces definition. Only available with `interface_type = "properties"`
447598
allow_unset: bool,
448599
}
449600

0 commit comments

Comments
 (0)