font_features.rs

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