mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 06:28:12 +08:00
Refuse record layouts wider than the frame tier's alignment
This commit is contained in:
@@ -155,6 +155,11 @@ impl Default for ElementWrite {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The widest alignment a record may need. Frames are a `Vec<u64>`, lanes
|
||||||
|
/// stride at a multiple of 8, and run slabs come from `alloc_scratch::<u64>`,
|
||||||
|
/// so nothing below a record can promise more.
|
||||||
|
pub const MAX_ALIGN: usize = 8;
|
||||||
|
|
||||||
/// A record layout: the element at offset 0, then the written attributes in
|
/// A record layout: the element at offset 0, then the written attributes in
|
||||||
/// canonical order (descending alignment, then size, then name, then level).
|
/// canonical order (descending alignment, then size, then name, then level).
|
||||||
/// Layouts are derived data, a pure function of the upstream write set.
|
/// Layouts are derived data, a pure function of the upstream write set.
|
||||||
@@ -198,8 +203,9 @@ impl Layout {
|
|||||||
|
|
||||||
/// The union of this layout's fields and `writes` over `element` at
|
/// The union of this layout's fields and `writes` over `element` at
|
||||||
/// `depth`, in canonical order. A (name, level) written at a different
|
/// `depth`, in canonical order. A (name, level) written at a different
|
||||||
/// size is a type conflict and panics; the census keeps declared names to
|
/// size is a type conflict and panics, as does an element or attribute
|
||||||
/// one type, so this only fires on wiring bugs.
|
/// wider than [`MAX_ALIGN`]; the census keeps declared names to one type,
|
||||||
|
/// so these only fire on wiring bugs.
|
||||||
pub fn with_writes(&self, depth: u8, element: ElementWrite, writes: &[FieldWrite]) -> Layout {
|
pub fn with_writes(&self, depth: u8, element: ElementWrite, writes: &[FieldWrite]) -> Layout {
|
||||||
let mut merged: Vec<FieldWrite> = self.fields.iter().map(FieldDesc::as_write).collect();
|
let mut merged: Vec<FieldWrite> = self.fields.iter().map(FieldDesc::as_write).collect();
|
||||||
for &write in writes {
|
for &write in writes {
|
||||||
@@ -208,6 +214,10 @@ impl Layout {
|
|||||||
None => merged.push(write),
|
None => merged.push(write),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert!(element.align <= MAX_ALIGN, "a record element aligns to at most {MAX_ALIGN} bytes, but this one needs {}", element.align);
|
||||||
|
for write in &merged {
|
||||||
|
assert!(write.align <= MAX_ALIGN, "attribute `{}` aligns to at most {MAX_ALIGN} bytes, but needs {}", write.name, write.align);
|
||||||
|
}
|
||||||
merged.sort_by(|a, b| b.align.cmp(&a.align).then(b.size.cmp(&a.size)).then(a.name.cmp(b.name)).then(a.level.cmp(&b.level)));
|
merged.sort_by(|a, b| b.align.cmp(&a.align).then(b.size.cmp(&a.size)).then(a.name.cmp(b.name)).then(a.level.cmp(&b.level)));
|
||||||
let mut offset = element.size;
|
let mut offset = element.size;
|
||||||
let mut align = element.align.max(1);
|
let mut align = element.align.max(1);
|
||||||
@@ -619,6 +629,18 @@ mod tests {
|
|||||||
assert_eq!(layout.align, 8);
|
assert_eq!(layout.align, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "a record element aligns to at most 8 bytes")]
|
||||||
|
fn an_over_aligned_element_is_refused_at_wiring() {
|
||||||
|
Layout::default().with_writes(0, element_write::<u128>(), &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "attribute `wide` aligns to at most 8 bytes")]
|
||||||
|
fn an_over_aligned_attribute_is_refused_at_wiring() {
|
||||||
|
Layout::default().with_writes(0, element_write::<f64>(), &[sized_field("wide", 16, 16)]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "two different types")]
|
#[should_panic(expected = "two different types")]
|
||||||
fn type_conflicts_panic() {
|
fn type_conflicts_panic() {
|
||||||
|
|||||||
Reference in New Issue
Block a user