mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-03 08:48:11 +08:00
Make Attribute an unsafe trait stating its re-park and glue coupling
This commit is contained in:
@@ -20,8 +20,24 @@ use std::sync::{LazyLock, Mutex};
|
|||||||
|
|
||||||
/// Declares an attribute name: one marker per name, fixing the value type and
|
/// Declares an attribute name: one marker per name, fixing the value type and
|
||||||
/// the name-specific default. Declare markers through the [`attribute!`]
|
/// the name-specific default. Declare markers through the [`attribute!`]
|
||||||
/// macro, which also registers them into the [`ATTRIBUTE_REGISTRY`].
|
/// macro, which also registers them into the [`ATTRIBUTE_REGISTRY`] and emits
|
||||||
pub trait Attribute: 'static {
|
/// an impl meeting the obligations below.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// [`REPARK`](Self::REPARK) must be `Some` for every marker whose
|
||||||
|
/// [`Value<'e>`](Self::Value) can carry a borrow shorter than `'static`. The
|
||||||
|
/// plain-value arm of the census writer retypes the value [`from_stored`] hands
|
||||||
|
/// it from the stored form's lifetime to the field's, which is only a relabel
|
||||||
|
/// where the value borrows nothing; a re-parking marker instead writes a
|
||||||
|
/// reference into the arena it is given.
|
||||||
|
///
|
||||||
|
/// [`from_stored`](Self::from_stored) must accept exactly the erased form
|
||||||
|
/// [`read_erased`](Self::read_erased) produces, and [`read_erased`] must read
|
||||||
|
/// its `ptr` as this marker's own `Value`. The two are each other's inverse
|
||||||
|
/// across every persistence seam, so a marker that reads one type and stores
|
||||||
|
/// another writes a value of the wrong type into the field.
|
||||||
|
pub unsafe trait Attribute: 'static {
|
||||||
/// The name as it appears in documents and diagnostics.
|
/// The name as it appears in documents and diagnostics.
|
||||||
const NAME: &'static str;
|
const NAME: &'static str;
|
||||||
/// The value type every read and write of this name shares. The lifetime
|
/// The value type every read and write of this name shares. The lifetime
|
||||||
@@ -267,7 +283,10 @@ macro_rules! attribute {
|
|||||||
$(#[$meta])*
|
$(#[$meta])*
|
||||||
$vis struct $marker;
|
$vis struct $marker;
|
||||||
|
|
||||||
impl $crate::attribute::Attribute for $marker {
|
// SAFETY: the reference-valued arms emit `REPARK`, the plain arm's value
|
||||||
|
// type cannot name `'e`, and `read_erased` and `from_stored` are emitted
|
||||||
|
// as each other's inverse.
|
||||||
|
unsafe impl $crate::attribute::Attribute for $marker {
|
||||||
const NAME: &'static str = $name;
|
const NAME: &'static str = $name;
|
||||||
type Value<'e> = ::core::option::Option<&'e $value>;
|
type Value<'e> = ::core::option::Option<&'e $value>;
|
||||||
|
|
||||||
@@ -306,7 +325,10 @@ macro_rules! attribute {
|
|||||||
$(#[$meta])*
|
$(#[$meta])*
|
||||||
$vis struct $marker;
|
$vis struct $marker;
|
||||||
|
|
||||||
impl $crate::attribute::Attribute for $marker {
|
// SAFETY: the reference-valued arms emit `REPARK`, the plain arm's value
|
||||||
|
// type cannot name `'e`, and `read_erased` and `from_stored` are emitted
|
||||||
|
// as each other's inverse.
|
||||||
|
unsafe impl $crate::attribute::Attribute for $marker {
|
||||||
const NAME: &'static str = $name;
|
const NAME: &'static str = $name;
|
||||||
type Value<'e> = &'e $value;
|
type Value<'e> = &'e $value;
|
||||||
$(
|
$(
|
||||||
@@ -341,7 +363,10 @@ macro_rules! attribute {
|
|||||||
$(#[$meta])*
|
$(#[$meta])*
|
||||||
$vis struct $marker;
|
$vis struct $marker;
|
||||||
|
|
||||||
impl $crate::attribute::Attribute for $marker {
|
// SAFETY: the reference-valued arms emit `REPARK`, the plain arm's value
|
||||||
|
// type cannot name `'e`, and `read_erased` and `from_stored` are emitted
|
||||||
|
// as each other's inverse.
|
||||||
|
unsafe impl $crate::attribute::Attribute for $marker {
|
||||||
const NAME: &'static str = $name;
|
const NAME: &'static str = $name;
|
||||||
type Value<'e> = $value;
|
type Value<'e> = $value;
|
||||||
$(
|
$(
|
||||||
@@ -497,7 +522,8 @@ mod tests {
|
|||||||
#[should_panic(expected = "two value types")]
|
#[should_panic(expected = "two value types")]
|
||||||
fn a_second_marker_at_a_different_type_panics() {
|
fn a_second_marker_at_a_different_type_panics() {
|
||||||
struct Conflict;
|
struct Conflict;
|
||||||
impl Attribute for Conflict {
|
// SAFETY: `bool` borrows nothing, so the plain-value arm is the right one.
|
||||||
|
unsafe impl Attribute for Conflict {
|
||||||
const NAME: &'static str = "opacity";
|
const NAME: &'static str = "opacity";
|
||||||
type Value<'e> = bool;
|
type Value<'e> = bool;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user