manifest/
serde_ext.rs

1// Copyright 2019 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//! Contains local mirrors and Serde annotations for FIDL types.
6//! See https://serde.rs/remote-derive.html.
7
8#![allow(missing_docs)]
9
10use fidl_fuchsia_fonts::{GenericFontFamily, Slant, Style2 as FidlStyle, Width};
11use serde::{Deserialize, Serialize};
12
13/// Generates Serde serialize and deserialize methods for types of `Option<T>`, where `T` is a type
14/// defined in a remote crate and is mirrored in a local type (https://serde.rs/remote-derive.html).
15///
16/// On its own, Serde can't handle enums that wrap remote types. This works around that limitation
17/// for the very specific case of `Option<T>`.
18///
19/// Expands to a mod that can be used by Serde's `"with"` attribute.
20///
21/// Example:
22/// ```
23/// mod remote_crate {
24///     pub enum Magic8BallResponse {
25///         Yes, Maybe, No, TryAgainLater
26///     }
27/// }
28/// ```
29/// ```
30/// mod local_crate {
31///     use remote_crate::Magic8BallResponse;
32///     use serde::{Deserialize, Serialize};
33///
34///     #[derive(Deserialize, Serialize)]
35///     #[serde(with = "Magic8BallResponse")]
36///     pub enum Magic8BallResponseDef {
37///         Yes, Maybe, No, TryAgainLater
38///     }
39///
40///     derive_opt!(
41///         OptMagic8BallResponse,
42///         Magic8BallResponse,
43///         Magic8BallResponseDef,
44///         "Magic8BallResponseDef");
45///
46///     #[derive(Deserialize, Serialize)]
47///     pub struct Responses {
48///         present: Magic8BallResponse,
49///         #[serde(with = "OptMagic8BallResponse")]
50///         hazy: Option<Magic8BallResponse>,
51///     }
52/// }
53///
54/// ```
55///
56/// Parameters:
57/// - `module`: Name of the generated module, e.g. `OptFidlTypeSerde`.
58/// - `remote_type`: Name of the remote type being mirrored, e.g. `SomeFidlType`.
59/// - `local_type`: Name of the local type that's mirroring the remote type, e.g. `SomeFidlTypeDef`.
60/// - `local_type_str`: The same as `local_type`, but wrapped in quotes.
61macro_rules! derive_opt {
62    ($module:ident, $remote_type:ty, $local_type:ty, $local_type_str:expr) => {
63        #[allow(non_snake_case, dead_code, missing_docs, explicit_outlives_requirements)]
64        pub mod $module {
65            use super::*;
66            use serde::{Deserialize, Deserializer, Serialize, Serializer};
67
68            #[doc = "Implementation of Serde's serialize"]
69            pub fn serialize<S>(
70                value: &Option<$remote_type>,
71                serializer: S,
72            ) -> Result<S::Ok, S::Error>
73            where
74                S: Serializer,
75            {
76                #[derive(Serialize)]
77                struct Wrapper<'a>(#[serde(with = $local_type_str)] &'a $remote_type);
78                value.as_ref().map(Wrapper).serialize(serializer)
79            }
80
81            #[doc = "Implementation of Serde's deserialize"]
82            pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<$remote_type>, D::Error>
83            where
84                D: Deserializer<'de>,
85            {
86                #[derive(Deserialize)]
87                struct Wrapper(#[serde(with = $local_type_str)] $remote_type);
88
89                let helper = Option::deserialize(deserializer)?;
90                Ok(helper.map(|Wrapper(external)| external))
91            }
92        }
93    };
94}
95
96/// Local mirror of [`fidl_fuchsia_fonts::Style2`], for use in JSON serialization.
97///
98/// We can't just use a Serde remote type for `Style2` here because there are lots of other required
99/// traits that are not derived for FIDL tables.
100///
101/// `Ord` is derived for use with the manifest generator's `TryMergeGroups` trait. The ordering is
102/// by necessity arbitrary, comparing each field in sequence, recursively comparing enum values and
103/// numbers.
104#[allow(missing_docs)]
105#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq, Hash, Ord, PartialOrd)]
106pub struct StyleOptions {
107    #[serde(default, with = "OptSlant", skip_serializing_if = "Option::is_none")]
108    pub slant: Option<Slant>,
109    #[serde(default, skip_serializing_if = "Option::is_none")]
110    pub weight: Option<u16>,
111    #[serde(default, with = "OptWidth", skip_serializing_if = "Option::is_none")]
112    pub width: Option<Width>,
113}
114
115impl From<FidlStyle> for StyleOptions {
116    fn from(fidl_style: FidlStyle) -> Self {
117        StyleOptions { slant: fidl_style.slant, weight: fidl_style.weight, width: fidl_style.width }
118    }
119}
120
121impl From<StyleOptions> for FidlStyle {
122    fn from(style_options: StyleOptions) -> Self {
123        FidlStyle {
124            slant: style_options.slant,
125            weight: style_options.weight,
126            width: style_options.width,
127            ..Default::default()
128        }
129    }
130}
131
132/// Local mirror of [`fidl_fuchsia_fonts::GenericFontFamily`], for use in JSON serialization.
133///
134/// Serialized values are in _kebab-case_, e.g. `"sans-serif"`.
135#[allow(missing_docs)]
136#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
137#[serde(remote = "GenericFontFamily", rename_all = "kebab-case")]
138pub enum GenericFontFamilyDef {
139    Serif,
140    SansSerif,
141    Monospace,
142    Cursive,
143    Fantasy,
144    SystemUi,
145    Emoji,
146    Math,
147    Fangsong,
148}
149
150derive_opt!(OptGenericFontFamily, GenericFontFamily, GenericFontFamilyDef, "GenericFontFamilyDef");
151
152/// Local mirror of [`fidl_fuchsia_fonts::Slant`], for use in JSON serialization.
153///
154/// Serialized values are _lowercase_, e.g. `"italic"`.
155#[allow(missing_docs)]
156#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
157#[serde(remote = "Slant", rename_all = "lowercase")]
158pub enum SlantDef {
159    Upright,
160    Italic,
161    Oblique,
162}
163
164derive_opt!(OptSlant, Slant, SlantDef, "SlantDef");
165
166/// Local mirror of [`fidl_fuchsia_fonts::Width`], for use in JSON serialization.
167///
168/// Serialized values are in _kebab-case_, e.g. `"semi-condensed"`.
169#[allow(missing_docs)]
170#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
171#[serde(remote = "Width", rename_all = "kebab-case")]
172pub enum WidthDef {
173    UltraCondensed,
174    ExtraCondensed,
175    Condensed,
176    SemiCondensed,
177    Normal,
178    SemiExpanded,
179    Expanded,
180    ExtraExpanded,
181    UltraExpanded,
182}
183
184derive_opt!(OptWidth, Width, WidthDef, "WidthDef");