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}