diff --git a/read-fonts/generated/generated_test_conditions.rs b/read-fonts/generated/generated_test_conditions.rs index 35cef2854..de8c0f2f0 100644 --- a/read-fonts/generated/generated_test_conditions.rs +++ b/read-fonts/generated/generated_test_conditions.rs @@ -120,6 +120,8 @@ impl GotFlags { pub const FOO: Self = Self { bits: 0x0001 }; pub const BAR: Self = Self { bits: 0x0002 }; + + pub const BAZ: Self = Self { bits: 0x0004 }; } impl GotFlags { @@ -133,7 +135,7 @@ impl GotFlags { #[inline] pub const fn all() -> Self { Self { - bits: Self::FOO.bits | Self::BAR.bits, + bits: Self::FOO.bits | Self::BAR.bits | Self::BAZ.bits, } } @@ -351,7 +353,8 @@ impl std::ops::Not for GotFlags { impl std::fmt::Debug for GotFlags { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let members: &[(&str, Self)] = &[("FOO", Self::FOO), ("BAR", Self::BAR)]; + let members: &[(&str, Self)] = + &[("FOO", Self::FOO), ("BAR", Self::BAR), ("BAZ", Self::BAZ)]; let mut first = true; for (name, value) in members { if self.contains(*value) { @@ -416,6 +419,7 @@ impl<'a> From for FieldType<'a> { pub struct FlagDayMarker { foo_byte_start: Option, bar_byte_start: Option, + baz_byte_start: Option, } impl FlagDayMarker { @@ -435,6 +439,10 @@ impl FlagDayMarker { let start = self.bar_byte_start?; Some(start..start + u16::RAW_BYTE_LEN) } + fn baz_byte_range(&self) -> Option> { + let start = self.baz_byte_start?; + Some(start..start + u16::RAW_BYTE_LEN) + } } impl<'a> FontRead<'a> for FlagDay<'a> { @@ -456,9 +464,17 @@ impl<'a> FontRead<'a> for FlagDay<'a> { flags .contains(GotFlags::BAR) .then(|| cursor.advance::()); + let baz_byte_start = flags + .intersects(GotFlags::BAZ | GotFlags::FOO) + .then(|| cursor.position()) + .transpose()?; + flags + .intersects(GotFlags::BAZ | GotFlags::FOO) + .then(|| cursor.advance::()); cursor.finish(FlagDayMarker { foo_byte_start, bar_byte_start, + baz_byte_start, }) } } @@ -485,6 +501,11 @@ impl<'a> FlagDay<'a> { let range = self.shape.bar_byte_range()?; Some(self.data.read_at(range.start).unwrap()) } + + pub fn baz(&self) -> Option { + let range = self.shape.baz_byte_range()?; + Some(self.data.read_at(range.start).unwrap()) + } } #[cfg(feature = "traversal")] @@ -499,6 +520,9 @@ impl<'a> SomeTable<'a> for FlagDay<'a> { 1usize => Some(Field::new("flags", self.flags())), 2usize if flags.contains(GotFlags::FOO) => Some(Field::new("foo", self.foo().unwrap())), 3usize if flags.contains(GotFlags::BAR) => Some(Field::new("bar", self.bar().unwrap())), + 4usize if flags.intersects(GotFlags::BAZ | GotFlags::FOO) => { + Some(Field::new("baz", self.baz().unwrap())) + } _ => None, } } diff --git a/read-fonts/src/codegen_test.rs b/read-fonts/src/codegen_test.rs index 3e08bd964..7ce942364 100644 --- a/read-fonts/src/codegen_test.rs +++ b/read-fonts/src/codegen_test.rs @@ -153,6 +153,9 @@ pub mod conditions { if flags.contains(GotFlags::BAR) { buf = buf.push(0xba4_u16); } + if flags.contains(GotFlags::FOO) || flags.contains(GotFlags::BAZ) { + buf = buf.push(0xba2_u16); + } buf } @@ -170,6 +173,7 @@ pub mod conditions { let table = FlagDay::read(data.font_data()).unwrap(); assert_eq!(table.foo(), Some(0xf00)); assert!(table.bar().is_none()); + assert_eq!(table.baz(), Some(0xba2)); } #[test] @@ -178,6 +182,16 @@ pub mod conditions { let table = FlagDay::read(data.font_data()).unwrap(); assert!(table.foo().is_none()); assert_eq!(table.bar(), Some(0xba4)); + assert!(table.baz().is_none()); + } + + #[test] + fn flags_baz() { + let data = make_flag_data(GotFlags::BAZ); + let table = FlagDay::read(data.font_data()).unwrap(); + assert!(table.foo().is_none()); + assert!(table.bar().is_none()); + assert_eq!(table.baz(), Some(0xba2)); } #[test] @@ -186,5 +200,6 @@ pub mod conditions { let table = FlagDay::read(data.font_data()).unwrap(); assert_eq!(table.foo(), Some(0xf00)); assert_eq!(table.bar(), Some(0xba4)); + assert_eq!(table.baz(), Some(0xba2)); } } diff --git a/resources/codegen_inputs/test_conditions.rs b/resources/codegen_inputs/test_conditions.rs index 2e8a378d3..a085421d1 100644 --- a/resources/codegen_inputs/test_conditions.rs +++ b/resources/codegen_inputs/test_conditions.rs @@ -16,6 +16,7 @@ table MajorMinorVersion { flags u16 GotFlags { FOO = 0x0001, BAR = 0x0002, + BAZ = 0x0004, } table FlagDay { @@ -25,4 +26,6 @@ table FlagDay { foo: u16, #[if_flag($flags, GotFlags::BAR)] bar: u16, + #[if_cond(any_flag($flags, GotFlags::BAZ, GotFlags::FOO))] + baz: u16, } diff --git a/write-fonts/generated/generated_test_conditions.rs b/write-fonts/generated/generated_test_conditions.rs index be0db4ee2..91e1dec8b 100644 --- a/write-fonts/generated/generated_test_conditions.rs +++ b/write-fonts/generated/generated_test_conditions.rs @@ -109,6 +109,7 @@ pub struct FlagDay { pub flags: GotFlags, pub foo: Option, pub bar: Option, + pub baz: Option, } impl FlagDay { @@ -138,6 +139,14 @@ impl FontWrite for FlagDay { .expect("missing conditional field should have failed validation") .write_into(writer) }); + self.flags + .intersects(GotFlags::BAZ | GotFlags::FOO) + .then(|| { + self.baz + .as_ref() + .expect("missing conditional field should have failed validation") + .write_into(writer) + }); } fn table_type(&self) -> TableType { TableType::Named("FlagDay") @@ -164,6 +173,14 @@ impl Validate for FlagDay { ctx.report("BAR is set but 'bar' is None") } }); + ctx.in_field("baz", |ctx| { + if !(flags.intersects(GotFlags::BAZ | GotFlags::FOO)) && self.baz.is_some() { + ctx.report("if_cond is not satisfied but 'baz' is present."); + } + if (flags.intersects(GotFlags::BAZ | GotFlags::FOO)) && self.baz.is_none() { + ctx.report("if_cond is satisfied by 'baz' is not present."); + } + }); }) } } @@ -175,6 +192,7 @@ impl<'a> FromObjRef> for FlagD flags: obj.flags(), foo: obj.foo(), bar: obj.bar(), + baz: obj.baz(), } } } diff --git a/write-fonts/src/codegen_test.rs b/write-fonts/src/codegen_test.rs index 892d49f2b..40c3da1c3 100644 --- a/write-fonts/src/codegen_test.rs +++ b/write-fonts/src/codegen_test.rs @@ -95,10 +95,25 @@ pub mod conditions { crate::dump_table(&flags_are_wrong).unwrap(); } + #[test] + #[should_panic(expected = "if_cond is not satisfied but 'baz' is present.")] + fn field_present_flag_missing_any_flag() { + let mut flags_are_wrong = FlagDay::new(42, GotFlags::empty()); + flags_are_wrong.baz = Some(0xf00); + crate::dump_table(&flags_are_wrong).unwrap(); + } + #[test] #[should_panic(expected = "FOO is set but 'foo' is None")] fn flag_present_field_missing() { let flags_are_wrong = FlagDay::new(42, GotFlags::FOO); crate::dump_table(&flags_are_wrong).unwrap(); } + + #[test] + #[should_panic(expected = "if_cond is satisfied by 'baz' is not present.")] + fn flag_present_field_missing_any_flags() { + let flags_are_wrong = FlagDay::new(42, GotFlags::BAZ); + crate::dump_table(&flags_are_wrong).unwrap(); + } }