#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FontFace {
pub family: &'static str,
pub bytes: &'static [u8],
}
impl FontFace {
pub const fn new(family: &'static str, bytes: &'static [u8]) -> Self {
Self { family, bytes }
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct NativeTypefaces {
pub button: Option<FontFace>,
pub body: Option<FontFace>,
}
impl NativeTypefaces {
pub const fn uniform(face: FontFace) -> Self {
Self {
button: Some(face),
body: Some(face),
}
}
pub const fn is_empty(&self) -> bool {
self.button.is_none() && self.body.is_none()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::theme::Theme;
static DISPLAY: &[u8] = b"display-face-bytes";
static BODY: &[u8] = b"body-face-bytes";
fn display() -> FontFace {
FontFace::new("Acme Display", DISPLAY)
}
fn body() -> FontFace {
FontFace::new("Acme Text", BODY)
}
#[test]
fn builder_attach_then_theme_extension_round_trips() {
let theme = Theme::builder(Theme::neutral())
.extension(NativeTypefaces {
button: Some(display()),
body: Some(body()),
})
.build();
let faces = theme
.extension::<NativeTypefaces>()
.expect("attached just above");
assert_eq!(faces.button, Some(display()));
assert_eq!(faces.body, Some(body()));
assert_eq!(faces.button.expect("set").bytes, DISPLAY);
}
#[test]
fn direct_insert_round_trips_too() {
let mut theme = Theme::neutral();
theme.extensions.insert(NativeTypefaces::uniform(body()));
assert_eq!(
theme.extension::<NativeTypefaces>(),
Some(&NativeTypefaces::uniform(body()))
);
}
#[test]
fn re_attaching_replaces_last_write_wins() {
let theme = Theme::builder(Theme::neutral())
.extension(NativeTypefaces::uniform(display()))
.extension(NativeTypefaces::uniform(body()))
.build();
assert_eq!(
theme.extension::<NativeTypefaces>(),
Some(&NativeTypefaces::uniform(body()))
);
}
#[test]
fn uniform_sets_both_slots_and_is_not_empty() {
let faces = NativeTypefaces::uniform(body());
assert_eq!(faces.button, Some(body()));
assert_eq!(faces.body, Some(body()));
assert!(!faces.is_empty());
}
#[test]
fn default_leaves_both_slots_unset() {
let faces = NativeTypefaces::default();
assert!(faces.button.is_none());
assert!(faces.body.is_none());
assert!(faces.is_empty());
assert!(
!NativeTypefaces {
button: Some(display()),
..NativeTypefaces::default()
}
.is_empty()
);
}
#[test]
fn no_core_baseline_attaches_this_extension() {
assert!(Theme::neutral().extension::<NativeTypefaces>().is_none());
}
#[test]
fn theme_equality_ignores_a_face_swap() {
let with_display = Theme::builder(Theme::neutral())
.extension(NativeTypefaces::uniform(display()))
.build();
let with_body = Theme::builder(Theme::neutral())
.extension(NativeTypefaces::uniform(body()))
.build();
assert_eq!(with_display, with_body);
assert_ne!(
with_display.extension::<NativeTypefaces>(),
with_body.extension::<NativeTypefaces>(),
"the payloads themselves still differ — which is what a consumer \
keys off"
);
}
}