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 super::*;
62    use fidl_fuchsia_intl::{CalendarId, LocaleId, Profile, TemperatureUnit};
63
64    #[test]
65    fn test_combinations() {
66        let mut expected = Profile::default();
67        expected.locales = Some(vec![LocaleId { id: "en-US".to_string() }]);
68        expected.temperature_unit = Some(TemperatureUnit::Fahrenheit);
69        expected.calendars = Some(vec![CalendarId { id: "gregory".to_string() }]);
70
71        let calendars = vec![CalendarId { id: "gregory".to_string() }];
72        let time_zones = None;
73
74        let actual = fable! {
75            Profile {
76                locales: Some(vec![LocaleId { id: "en-US".to_string() }]),
77                temperature_unit: TemperatureUnit::Fahrenheit,
78                calendars,
79                time_zones,
80            }
81        };
82
83        assert_eq!(actual, expected);
84    }
85}