1use schemars::{
2 schema::{InstanceType, Schema, SchemaObject, SingleOrVec},
3 JsonSchema,
4};
5
6macro_rules! create_definitions {
7 ($($(#[$meta:meta])* ($name:ident, $idx:expr)),* $(,)?) => {
8
9 /// The OpenType features that can be configured for a given font.
10 #[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
11 pub struct FontFeatures {
12 enabled: u64,
13 disabled: u64,
14 }
15
16 impl FontFeatures {
17 $(
18 /// Get the current value of the corresponding OpenType feature
19 pub fn $name(&self) -> Option<bool> {
20 if (self.enabled & (1 << $idx)) != 0 {
21 Some(true)
22 } else if (self.disabled & (1 << $idx)) != 0 {
23 Some(false)
24 } else {
25 None
26 }
27 }
28 )*
29
30 /// Get the tag name list of the font OpenType features
31 /// only enabled or disabled features are returned
32 #[cfg(target_os = "windows")]
33 pub fn tag_value_list(&self) -> Vec<(String, bool)> {
34 let mut result = Vec::new();
35 $(
36 {
37 let value = if (self.enabled & (1 << $idx)) != 0 {
38 Some(true)
39 } else if (self.disabled & (1 << $idx)) != 0 {
40 Some(false)
41 } else {
42 None
43 };
44 if let Some(enable) = value {
45 let tag_name = stringify!($name).to_owned();
46 result.push((tag_name, enable));
47 }
48 }
49 )*
50 result
51 }
52 }
53
54 impl std::fmt::Debug for FontFeatures {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 let mut debug = f.debug_struct("FontFeatures");
57 $(
58 if let Some(value) = self.$name() {
59 debug.field(stringify!($name), &value);
60 };
61 )*
62 debug.finish()
63 }
64 }
65
66 impl<'de> serde::Deserialize<'de> for FontFeatures {
67 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68 where
69 D: serde::Deserializer<'de>,
70 {
71 use serde::de::{MapAccess, Visitor};
72 use std::fmt;
73
74 struct FontFeaturesVisitor;
75
76 impl<'de> Visitor<'de> for FontFeaturesVisitor {
77 type Value = FontFeatures;
78
79 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
80 formatter.write_str("a map of font features")
81 }
82
83 fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
84 where
85 M: MapAccess<'de>,
86 {
87 let mut enabled: u64 = 0;
88 let mut disabled: u64 = 0;
89
90 while let Some((key, value)) = access.next_entry::<String, Option<bool>>()? {
91 let idx = match key.as_str() {
92 $(stringify!($name) => $idx,)*
93 _ => continue,
94 };
95 match value {
96 Some(true) => enabled |= 1 << idx,
97 Some(false) => disabled |= 1 << idx,
98 None => {}
99 };
100 }
101 Ok(FontFeatures { enabled, disabled })
102 }
103 }
104
105 let features = deserializer.deserialize_map(FontFeaturesVisitor)?;
106 Ok(features)
107 }
108 }
109
110 impl serde::Serialize for FontFeatures {
111 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112 where
113 S: serde::Serializer,
114 {
115 use serde::ser::SerializeMap;
116
117 let mut map = serializer.serialize_map(None)?;
118
119 $(
120 {
121 let feature = stringify!($name);
122 if let Some(value) = self.$name() {
123 map.serialize_entry(feature, &value)?;
124 }
125 }
126 )*
127
128 map.end()
129 }
130 }
131
132 impl JsonSchema for FontFeatures {
133 fn schema_name() -> String {
134 "FontFeatures".into()
135 }
136
137 fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> Schema {
138 let mut schema = SchemaObject::default();
139 let properties = &mut schema.object().properties;
140 let feature_schema = Schema::Object(SchemaObject {
141 instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Boolean))),
142 ..Default::default()
143 });
144
145 $(
146 properties.insert(stringify!($name).to_owned(), feature_schema.clone());
147 )*
148
149 schema.into()
150 }
151 }
152 };
153}
154
155create_definitions!(
156 (calt, 0),
157 (case, 1),
158 (cpsp, 2),
159 (frac, 3),
160 (liga, 4),
161 (onum, 5),
162 (ordn, 6),
163 (pnum, 7),
164 (ss01, 8),
165 (ss02, 9),
166 (ss03, 10),
167 (ss04, 11),
168 (ss05, 12),
169 (ss06, 13),
170 (ss07, 14),
171 (ss08, 15),
172 (ss09, 16),
173 (ss10, 17),
174 (ss11, 18),
175 (ss12, 19),
176 (ss13, 20),
177 (ss14, 21),
178 (ss15, 22),
179 (ss16, 23),
180 (ss17, 24),
181 (ss18, 25),
182 (ss19, 26),
183 (ss20, 27),
184 (subs, 28),
185 (sups, 29),
186 (swsh, 30),
187 (titl, 31),
188 (tnum, 32),
189 (zero, 33),
190);