mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 20:08:12 +08:00
Make the sources fields private and normalize them on every mutation
This commit is contained in:
@@ -30,22 +30,14 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
|
|||||||
call_argument: concrete!(Context),
|
call_argument: concrete!(Context),
|
||||||
inputs: vec![NodeInput::import(core_types::Type::Fn(Box::new(concrete!(Context)), Box::new(generic!(T))), 0)],
|
inputs: vec![NodeInput::import(core_types::Type::Fn(Box::new(concrete!(Context)), Box::new(generic!(T))), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render_intermediate::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render_intermediate::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
context_features: graphene_std::ContextDependencies::new(ContextFeatures::VARARGS, ContextFeatures::INDEX),
|
||||||
extract: ContextFeatures::VARARGS,
|
|
||||||
inject: ContextFeatures::INDEX,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
call_argument: concrete!(Context),
|
call_argument: concrete!(Context),
|
||||||
inputs: vec![NodeInput::scope(graphene_std::platform_application_io::try_wgpu_executor::IDENTIFIER), NodeInput::node(NodeId(0), 0)],
|
inputs: vec![NodeInput::scope(graphene_std::platform_application_io::try_wgpu_executor::IDENTIFIER), NodeInput::node(NodeId(0), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
context_features: graphene_std::ContextDependencies::new(ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS, ContextFeatures::empty()),
|
||||||
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
|
||||||
inject: ContextFeatures::empty(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
@@ -56,22 +48,14 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
|
|||||||
NodeInput::node(NodeId(1), 0),
|
NodeInput::node(NodeId(1), 0),
|
||||||
],
|
],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_cache::render_output_cache::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_cache::render_output_cache::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
context_features: graphene_std::ContextDependencies::new(ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS, ContextFeatures::VARARGS),
|
||||||
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
|
||||||
inject: ContextFeatures::VARARGS,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
call_argument: concrete!(Context),
|
call_argument: concrete!(Context),
|
||||||
inputs: vec![NodeInput::scope(graphene_std::render_pixel_preview::pixel_preview_pipeline::IDENTIFIER), NodeInput::node(NodeId(2), 0)],
|
inputs: vec![NodeInput::scope(graphene_std::render_pixel_preview::pixel_preview_pipeline::IDENTIFIER), NodeInput::node(NodeId(2), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_pixel_preview::render_pixel_preview::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_pixel_preview::render_pixel_preview::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
context_features: graphene_std::ContextDependencies::new(ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS, ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS),
|
||||||
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
|
||||||
inject: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
@@ -81,23 +65,18 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
|
|||||||
NodeInput::node(NodeId(3), 0),
|
NodeInput::node(NodeId(3), 0),
|
||||||
],
|
],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_background::render_background::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_background::render_background::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
context_features: graphene_std::ContextDependencies::new(ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS, ContextFeatures::empty()),
|
||||||
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
|
||||||
inject: ContextFeatures::empty(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
call_argument: concrete!(graphene_std::application_io::RenderConfig),
|
call_argument: concrete!(graphene_std::application_io::RenderConfig),
|
||||||
inputs: vec![NodeInput::node(NodeId(4), 0)],
|
inputs: vec![NodeInput::node(NodeId(4), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::create_context::IDENTIFIER),
|
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::create_context::IDENTIFIER),
|
||||||
context_features: graphene_std::ContextDependencies {
|
// We add the extract index annotation here to force the compiler to add a context nullification node before this node so the render context is properly nullified so the render cache node can do its's work
|
||||||
// We add the extract index annotation here to force the compiler to add a context nullification node before this node so the render context is properly nullified so the render cache node can do its's work
|
context_features: graphene_std::ContextDependencies::new(
|
||||||
extract: ContextFeatures::INDEX,
|
ContextFeatures::INDEX,
|
||||||
inject: ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME | ContextFeatures::POINTER_POSITION | ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME | ContextFeatures::POINTER_POSITION | ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
|
||||||
..Default::default()
|
),
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -199,18 +199,52 @@ impl ContextFeatures {
|
|||||||
pub struct ContextDependencies {
|
pub struct ContextDependencies {
|
||||||
pub extract: ContextFeatures,
|
pub extract: ContextFeatures,
|
||||||
pub inject: ContextFeatures,
|
pub inject: ContextFeatures,
|
||||||
/// Must stay sorted.
|
|
||||||
#[cfg_attr(feature = "serde", serde(default, deserialize_with = "deserialize_sorted_sources"))]
|
#[cfg_attr(feature = "serde", serde(default, deserialize_with = "deserialize_sorted_sources"))]
|
||||||
pub sources: Vec<SourceId>,
|
sources: Vec<SourceId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextDependencies {
|
||||||
|
pub fn new(extract: ContextFeatures, inject: ContextFeatures) -> Self {
|
||||||
|
Self { extract, inject, sources: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sources(&self) -> &[SourceId] {
|
||||||
|
&self.sources
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_sources(&mut self, sources: &[SourceId]) {
|
||||||
|
merge_sorted_sources(&mut self.sources, sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_sources(sources: &[SourceId]) -> Self {
|
||||||
|
let mut dependencies = Self::default();
|
||||||
|
dependencies.add_sources(sources);
|
||||||
|
dependencies
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, graphene_hash::CacheHash, dyn_any::DynAny, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, graphene_hash::CacheHash, dyn_any::DynAny, Default)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct ContextModification {
|
pub struct ContextModification {
|
||||||
pub features: ContextFeatures,
|
pub features: ContextFeatures,
|
||||||
/// Must stay sorted.
|
|
||||||
#[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_sorted_sources"))]
|
#[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_sorted_sources"))]
|
||||||
pub sources: Vec<SourceId>,
|
sources: Vec<SourceId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextModification {
|
||||||
|
pub fn sources(&self) -> &[SourceId] {
|
||||||
|
&self.sources
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_sources(&mut self, sources: &[SourceId]) {
|
||||||
|
merge_sorted_sources(&mut self.sources, sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_sources(features: ContextFeatures, sources: &[SourceId]) -> Self {
|
||||||
|
let mut modification = Self { features, sources: Vec::new() };
|
||||||
|
modification.add_sources(sources);
|
||||||
|
modification
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restores the sorted-and-deduplicated invariant that `contains` and `difference`
|
/// Restores the sorted-and-deduplicated invariant that `contains` and `difference`
|
||||||
@@ -251,10 +285,12 @@ impl core::ops::BitAndAssign<ContextFeatures> for ContextModification {
|
|||||||
|
|
||||||
impl ContextModification {
|
impl ContextModification {
|
||||||
pub fn contains(&self, other: &Self) -> bool {
|
pub fn contains(&self, other: &Self) -> bool {
|
||||||
|
debug_assert!(self.sources.is_sorted() && other.sources.is_sorted());
|
||||||
self.features.contains(other.features) && other.sources.iter().all(|id| self.sources.binary_search(id).is_ok())
|
self.features.contains(other.features) && other.sources.iter().all(|id| self.sources.binary_search(id).is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn difference(&self, other: &Self) -> Self {
|
pub fn difference(&self, other: &Self) -> Self {
|
||||||
|
debug_assert!(other.sources.is_sorted());
|
||||||
Self {
|
Self {
|
||||||
features: self.features.difference(other.features),
|
features: self.features.difference(other.features),
|
||||||
sources: self.sources.iter().copied().filter(|id| other.sources.binary_search(id).is_err()).collect(),
|
sources: self.sources.iter().copied().filter(|id| other.sources.binary_search(id).is_err()).collect(),
|
||||||
@@ -266,12 +302,12 @@ impl ContextModification {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sorts and deduplicates unconditionally, so the result is ordered no matter what
|
||||||
|
/// order the inputs arrived in.
|
||||||
pub fn merge_sorted_sources(sources: &mut Vec<SourceId>, other: &[SourceId]) {
|
pub fn merge_sorted_sources(sources: &mut Vec<SourceId>, other: &[SourceId]) {
|
||||||
for &id in other {
|
sources.extend_from_slice(other);
|
||||||
if let Err(insert_at) = sources.binary_search(&id) {
|
sources.sort_unstable();
|
||||||
sources.insert(insert_at, id);
|
sources.dedup();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&[ContextFeature]> for ContextDependencies {
|
impl From<&[ContextFeature]> for ContextDependencies {
|
||||||
@@ -1561,6 +1597,17 @@ mod context_impl_tests {
|
|||||||
assert!(matches!(empty.vararg(0), Err(VarArgsResult::NoVarArgs)));
|
assert!(matches!(empty.vararg(0), Err(VarArgsResult::NoVarArgs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sources_are_normalized_regardless_of_insertion_order() {
|
||||||
|
let mut dependencies = ContextDependencies::default();
|
||||||
|
dependencies.add_sources(&[9, 3, 9]);
|
||||||
|
dependencies.add_sources(&[5, 1]);
|
||||||
|
assert_eq!(dependencies.sources(), &[1, 3, 5, 9]);
|
||||||
|
|
||||||
|
let modification = ContextModification::from_sources(ContextFeatures::empty(), &[7, 2, 7]);
|
||||||
|
assert_eq!(modification.sources(), &[2, 7]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn a_snapshot_preserves_an_absent_position_axis() {
|
fn a_snapshot_preserves_an_absent_position_axis() {
|
||||||
let arena = Arena::new(64).unwrap();
|
let arena = Arena::new(64).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user