fable_lib/lib.rs
1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#[macro_export]
6/// Shorthand for creating a FIDL table in a way that will not cause build breakages if new fields
7/// are added to the table in the future.
8///
9/// - The values do not have to be wrapped in `Some`; this is inferred automatically.
10/// - Empty fields can either be omitted or explicitly set to `None`.
11/// - When a field name matches the name of an in-scope variable or parameter, a shorthand notation
12/// is available (just like in Rust struct initializers).
13///
14/// Example:
15/// ```rust
16/// use fidl_fuchsia_intl::{CalendarId, LocaleId, Profile, TemperatureUnit};
17///
18/// let calendars = vec![CalendarId { id: "gregorian".to_string() }];
19/// let time_zones = None;
20///
21/// let table = fable! {
22/// Profile {
23/// locales: Some(vec![LocaleId { id: "en-US".to_string() }]),
24/// // `Some` can be omitted
25/// temperature_unit: TemperatureUnit::Fahrenheit,
26/// // Shorthand notation when the field and variable names match
27/// calendars,
28/// time_zones,
29/// }
30/// };
31/// ```
32macro_rules! fable {
33 // Entry point
34 ($fidl_type:path { $($rest:tt)* }) => {
35 {
36 use $fidl_type as FidlType;
37 let mut _table = FidlType::default();
38 fable!(@internal _table $($rest)*);
39 _table
40 }
41 };
42
43 // Full notation
44 (@internal $table:ident $field:ident : $value:expr, $($rest:tt)*) => {
45 $table.$field = ($value).into();
46 fable!(@internal $table $($rest)*);
47 };
48
49 // Shorthand notation
50 (@internal $table:ident $field:ident, $($rest:tt)*) => {
51 $table.$field = $field.into();
52 fable!(@internal $table $($rest)*);
53 };
54
55 // End
56 (@internal $table:ident) => {};
57}
58
59#[cfg(test)]
60mod tests {
61 use fidl_fuchsia_intl::{CalendarId, LocaleId, Profile, TemperatureUnit};
62
63 #[test]
64 fn test_combinations() {
65 let mut expected = Profile::default();
66 expected.locales = Some(vec![LocaleId { id: "en-US".to_string() }]);
67 expected.temperature_unit = Some(TemperatureUnit::Fahrenheit);
68 expected.calendars = Some(vec![CalendarId { id: "gregory".to_string() }]);
69
70 let calendars = vec![CalendarId { id: "gregory".to_string() }];
71 let time_zones = None;
72
73 let actual = fable! {
74 Profile {
75 locales: Some(vec![LocaleId { id: "en-US".to_string() }]),
76 temperature_unit: TemperatureUnit::Fahrenheit,
77 calendars,
78 time_zones,
79 }
80 };
81
82 assert_eq!(actual, expected);
83 }
84}