mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 08:08:11 +08:00
Structure record stack rewinds as scope guards and make reserve unsafe
This commit is contained in:
@@ -19,21 +19,13 @@ use raster_types::BitmapMut;
|
||||
use raster_types::Image;
|
||||
use raster_types::{CPU, Raster};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, dyn_any::DynAny)]
|
||||
pub struct BrushStampGenerator<P: Pixel + Alpha> {
|
||||
color: P,
|
||||
feather_exponent: f32,
|
||||
transform: DAffine2,
|
||||
}
|
||||
|
||||
// SAFETY: `Static` is `Self` with `P` at its own static projection.
|
||||
unsafe impl<P: Pixel + Alpha + dyn_any::StaticTypeSized> dyn_any::StaticType for BrushStampGenerator<P>
|
||||
where
|
||||
P::Static: Pixel + Alpha,
|
||||
{
|
||||
type Static = BrushStampGenerator<P::Static>;
|
||||
}
|
||||
|
||||
impl<P: Pixel + Alpha> Transform for BrushStampGenerator<P> {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
self.transform
|
||||
|
||||
@@ -246,8 +246,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn scope_fixture<'a>(generations: &'a [(SourceId, u64)], arena: &'a Arena) -> EvalScope<'a> {
|
||||
core_types::record::stack::reserve(1 << 16);
|
||||
EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { core_types::record::stack::reserve(1 << 16); } EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
}
|
||||
|
||||
fn element_layout<T: Clone + Send + Sync + core_types::StaticTypeSized>() -> core_types::record::Layout
|
||||
|
||||
@@ -538,8 +538,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn scope_fixture<'a>(generations: &'a [(SourceId, u64)], arena: &'a Arena) -> EvalScope<'a> {
|
||||
stack::reserve(1 << 16);
|
||||
EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { stack::reserve(1 << 16); } EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
}
|
||||
|
||||
fn f64_layout(names: &[&'static str]) -> Layout {
|
||||
@@ -579,8 +579,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn reserve_for(layouts: &[&Layout]) {
|
||||
stack::reserve(layouts.iter().map(|layout| layout.frame_bytes()).sum::<usize>().max(1 << 12));
|
||||
}
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { stack::reserve(layouts.iter().map(|layout| layout.frame_bytes()).sum::<usize>().max(1 << 12)); } }
|
||||
|
||||
fn install<N: Node<ContextImpl<'static>>>(mut node: N, meta: core_types::record::LayoutMeta, inputs: &[Option<&Layout>]) -> N {
|
||||
// The fixtures wire constants into every eager input, which the compiler
|
||||
@@ -1660,14 +1660,13 @@ mod tests {
|
||||
|
||||
let head = ctx.index_head();
|
||||
for (lane, element) in [(0u64, 10.), (1, 11.)] {
|
||||
let mark = stack::sp();
|
||||
let _lane_scope = unsafe { stack::ScopeGuard::enter() };
|
||||
let GPoll::Final(value) = node.eval(&ctx.promoted(&head, lane)) else {
|
||||
panic!("expected a final record at lane {lane}");
|
||||
};
|
||||
let rec = out.rec(&value);
|
||||
assert_eq!(unsafe { rec.element::<f64>() }, element, "lane {lane}");
|
||||
assert_eq!(unsafe { rec.read::<&[NodeId]>(offset) }, path.as_slice(), "lane {lane}");
|
||||
unsafe { stack::rewind(mark) };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -264,8 +264,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn scope_fixture<'a>(generations: &'a [(SourceId, u64)], arena: &'a Arena) -> EvalScope<'a> {
|
||||
stack::reserve(1 << 16);
|
||||
EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { stack::reserve(1 << 16); } EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
}
|
||||
|
||||
fn install<N: Node<ContextImpl<'static>>>(mut node: N, meta: record::LayoutMeta, inputs: &[Option<&Layout>]) -> N {
|
||||
@@ -841,13 +841,13 @@ mod tests {
|
||||
let wrap_out = Node::<ContextImpl>::layout(&wrapped).clone();
|
||||
let head = ctx.index_head();
|
||||
let group = {
|
||||
let mark = stack::sp();
|
||||
// SAFETY: the element is cloned out inside the scope, so no borrow
|
||||
// into the frame escapes it.
|
||||
let _scope = unsafe { stack::ScopeGuard::enter() };
|
||||
let GPoll::Final(value) = wrapped.eval(&ctx.promoted(&head, 0)) else {
|
||||
panic!("expected a final record");
|
||||
};
|
||||
let group = unsafe { record::borrow_element::<Graphic>(wrap_out.rec(&value)) }.clone();
|
||||
// SAFETY: the element was cloned out above, so no borrow into the frame remains.
|
||||
unsafe { stack::rewind(mark) };
|
||||
group
|
||||
};
|
||||
|
||||
|
||||
@@ -267,8 +267,8 @@ mod tests {
|
||||
|
||||
let probe = core_types::record::RecordLift::<RenderOutput, _>::new(ProbeNode);
|
||||
let layout = Node::<ContextImpl>::layout(&probe).clone();
|
||||
core_types::record::stack::reserve(layout.frame_bytes().max(1 << 12));
|
||||
let mut graph = CreateContextNode::new(probe, &layout);
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { core_types::record::stack::reserve(layout.frame_bytes().max(1 << 12)); } let mut graph = CreateContextNode::new(probe, &layout);
|
||||
// The executor resolves and installs the node's own layout at wiring;
|
||||
// without it the flip tail writes through the default empty layout.
|
||||
Node::<ContextImpl>::set_layout(
|
||||
|
||||
@@ -1044,8 +1044,8 @@ mod graphene_test {
|
||||
}
|
||||
|
||||
fn reserve_for(layouts: &[&Layout]) {
|
||||
stack::reserve(layouts.iter().map(|layout| layout.frame_bytes()).sum::<usize>().max(1 << 12));
|
||||
}
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { stack::reserve(layouts.iter().map(|layout| layout.frame_bytes()).sum::<usize>().max(1 << 12)); } }
|
||||
|
||||
/// Lifts a plain-element test source onto a record wire, returned beside its
|
||||
/// element-only layout for the generated node's constructor.
|
||||
|
||||
@@ -70,8 +70,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_image_color_palette() {
|
||||
core_types::record::stack::reserve(1 << 16);
|
||||
let arena = core_types::arena::Arena::new(1 << 22).unwrap();
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { core_types::record::stack::reserve(1 << 16); } let arena = core_types::arena::Arena::new(1 << 22).unwrap();
|
||||
let generations = [];
|
||||
let scope = core_types::context::EvalScope::new(None, None, None, &generations, &arena);
|
||||
let ctx = core_types::context::ContextImpl::root(&scope);
|
||||
|
||||
@@ -216,8 +216,8 @@ mod test {
|
||||
}
|
||||
|
||||
fn scope_fixture<'a>(generations: &'a [(SourceId, u64)], arena: &'a Arena) -> EvalScope<'a> {
|
||||
stack::reserve(1 << 12);
|
||||
EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { stack::reserve(1 << 12); } EvalScope::new(Some(0.5), None, None, generations, arena)
|
||||
}
|
||||
|
||||
struct VectorRows {
|
||||
|
||||
@@ -3870,8 +3870,8 @@ mod test {
|
||||
}
|
||||
#[test]
|
||||
fn path_length() {
|
||||
core_types::record::stack::reserve(1 << 16);
|
||||
let arena = core_types::arena::Arena::new(1 << 20).unwrap();
|
||||
// SAFETY: between evaluations, nothing served on the stack is live.
|
||||
unsafe { core_types::record::stack::reserve(1 << 16); } let arena = core_types::arena::Arena::new(1 << 20).unwrap();
|
||||
let generations = [];
|
||||
let scope = core_types::context::EvalScope::new(None, None, None, &generations, &arena);
|
||||
let ctx = core_types::context::ContextImpl::root(&scope);
|
||||
|
||||
Reference in New Issue
Block a user