mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
Make the dynamic node graph execution asynchronous (#1218)
* Make node graph execution async Make node macro generate async node implementations Start propagating async through the node system Async checkpoint Make Any<'i> Send + Sync Determine node io type using panic node Fix types for raster_node macro Finish porting node registry? Fix lifetime errors Remove Send + Sync requirements and start making node construction async Async MVP Fix tests Clippy fix * Fix nodes * Simplify lifetims for node macro + make node macro more modular * Reenable more nodes * Fix pasting images * Remove http test from brush node * Fix output type for cache node * Fix types for let scope * Fix formatting
This commit is contained in:
parent
5c7211cb30
commit
4bd9fbd073
40 changed files with 834 additions and 471 deletions
|
@ -60,6 +60,10 @@ where
|
|||
Self::Output: 'i + StaticTypeSized,
|
||||
Input: 'i + StaticTypeSized,
|
||||
{
|
||||
fn node_name(&self) -> &'static str {
|
||||
core::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn input_type(&self) -> TypeId {
|
||||
TypeId::of::<Input::Static>()
|
||||
}
|
||||
|
@ -121,6 +125,13 @@ impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<Box<dyn for<'a> Node<'a, I, Output =
|
|||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<&'i (dyn NodeIO<'i, I, Output = O> + 'i)> {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use crate::raster::image::{EditorApi, ExtractImageFrame};
|
||||
|
|
|
@ -22,7 +22,7 @@ pub struct AddParameterNode<Second> {
|
|||
second: Second,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(AddParameterNode)]
|
||||
#[node_macro::node_new(AddParameterNode)]
|
||||
fn add_parameter<U, T>(first: U, second: T) -> <U as Add<T>>::Output
|
||||
where
|
||||
U: Add<T>,
|
||||
|
@ -30,6 +30,24 @@ where
|
|||
first + second
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl<'input, U: 'input, T: 'input, S0: 'input> Node<'input, U> for AddParameterNode<S0>
|
||||
where
|
||||
U: Add<T>,
|
||||
S0: Node<'input, (), Output = T>,
|
||||
{
|
||||
type Output = <U as Add<T>>::Output;
|
||||
#[inline]
|
||||
fn eval(&'input self, first: U) -> Self::Output {
|
||||
let second = self.second.eval(());
|
||||
{
|
||||
{
|
||||
first + second
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MulParameterNode<Second> {
|
||||
second: Second,
|
||||
}
|
||||
|
@ -181,7 +199,7 @@ pub struct MapResultNode<I, E, Mn> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(MapResultNode<_I, _E>)]
|
||||
fn flat_map<_I, _E, N>(input: Result<_I, _E>, node: &'any_input N) -> Result<<N as Node<'input, _I>>::Output, _E>
|
||||
fn flat_map<_I, _E, N>(input: Result<_I, _E>, node: &'input N) -> Result<<N as Node<'input, _I>>::Output, _E>
|
||||
where
|
||||
N: for<'a> Node<'a, _I>,
|
||||
{
|
||||
|
@ -195,7 +213,7 @@ pub struct FlatMapResultNode<I, O, E, Mn> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(FlatMapResultNode<_I, _O, _E>)]
|
||||
fn flat_map<_I, _O, _E, N>(input: Result<_I, _E>, node: &'any_input N) -> Result<_O, _E>
|
||||
fn flat_map<_I, _O, _E, N>(input: Result<_I, _E>, node: &'input N) -> Result<_O, _E>
|
||||
where
|
||||
N: for<'a> Node<'a, _I, Output = Result<_O, _E>>,
|
||||
{
|
||||
|
|
|
@ -221,7 +221,7 @@ pub struct MapNode<MapFn> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(MapNode)]
|
||||
fn map_node<_Iter: Iterator, MapFnNode>(input: _Iter, map_fn: &'any_input MapFnNode) -> MapFnIterator<'input, _Iter, MapFnNode>
|
||||
fn map_node<_Iter: Iterator, MapFnNode>(input: _Iter, map_fn: &'input MapFnNode) -> MapFnIterator<'input, _Iter, MapFnNode>
|
||||
where
|
||||
MapFnNode: for<'any_input> Node<'any_input, _Iter::Item>,
|
||||
{
|
||||
|
@ -425,7 +425,7 @@ pub struct MapSndNode<First, Second, MapFn> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(MapSndNode< _First, _Second>)]
|
||||
fn map_snd_node<MapFn, _First, _Second>(input: (_First, _Second), map_fn: &'any_input MapFn) -> (_First, <MapFn as Node<'input, _Second>>::Output)
|
||||
fn map_snd_node<MapFn, _First, _Second>(input: (_First, _Second), map_fn: &'input MapFn) -> (_First, <MapFn as Node<'input, _Second>>::Output)
|
||||
where
|
||||
MapFn: for<'any_input> Node<'any_input, _Second>,
|
||||
{
|
||||
|
@ -449,7 +449,7 @@ pub struct ForEachNode<MapNode> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(ForEachNode)]
|
||||
fn map_node<_Iter: Iterator, MapNode>(input: _Iter, map_node: &'any_input MapNode) -> ()
|
||||
fn map_node<_Iter: Iterator, MapNode>(input: _Iter, map_node: &'input MapNode) -> ()
|
||||
where
|
||||
MapNode: for<'any_input> Node<'any_input, _Iter::Item, Output = ()> + 'input,
|
||||
{
|
||||
|
|
|
@ -329,12 +329,13 @@ impl<'a> AsRef<EditorApi<'a>> for EditorApi<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ExtractImageFrame;
|
||||
|
||||
impl<'a: 'input, 'input> Node<'input, EditorApi<'a>> for ExtractImageFrame {
|
||||
impl<'a: 'input, 'input> Node<'input, &'a EditorApi<'a>> for ExtractImageFrame {
|
||||
type Output = ImageFrame<Color>;
|
||||
fn eval(&'input self, mut editor_api: EditorApi<'a>) -> Self::Output {
|
||||
editor_api.image_frame.take().unwrap_or(ImageFrame::identity())
|
||||
fn eval(&'input self, editor_api: &'a EditorApi<'a>) -> Self::Output {
|
||||
editor_api.image_frame.clone().unwrap_or(ImageFrame::identity())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ struct SetNode<S, I, Storage, Index> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(SetNode<_S, _I>)]
|
||||
fn set_node<T, _S, _I>(value: T, storage: &'any_input mut _S, index: _I)
|
||||
fn set_node<T, _S, _I>(value: T, storage: &'input mut _S, index: _I)
|
||||
where
|
||||
_S: IndexMut<_I>,
|
||||
_S::Output: DerefMut<Target = T> + Sized,
|
||||
|
@ -25,7 +25,7 @@ struct GetNode<S, Storage> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(GetNode<_S>)]
|
||||
fn get_node<_S, I>(index: I, storage: &'any_input _S) -> &'input _S::Output
|
||||
fn get_node<_S, I>(index: I, storage: &'input _S) -> &'input _S::Output
|
||||
where
|
||||
_S: Index<I>,
|
||||
_S::Output: Sized,
|
||||
|
|
|
@ -32,6 +32,39 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AsyncComposeNode<First, Second, I> {
|
||||
first: First,
|
||||
second: Second,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<'i, 'f: 'i, 's: 'i, Input: 'static, First, Second> Node<'i, Input> for AsyncComposeNode<First, Second, Input>
|
||||
where
|
||||
First: Node<'i, Input>,
|
||||
First::Output: core::future::Future,
|
||||
Second: Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
|
||||
{
|
||||
type Output = core::pin::Pin<Box<dyn core::future::Future<Output = <Second as Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output>>::Output> + 'i>>;
|
||||
fn eval(&'i self, input: Input) -> Self::Output {
|
||||
Box::pin(async move {
|
||||
let arg = self.first.eval(input).await;
|
||||
self.second.eval(arg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, First, Second, Input: 'i> AsyncComposeNode<First, Second, Input>
|
||||
where
|
||||
First: Node<'i, Input>,
|
||||
First::Output: core::future::Future,
|
||||
Second: Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
|
||||
{
|
||||
pub const fn new(first: First, second: Second) -> Self {
|
||||
AsyncComposeNode::<First, Second, Input> { first, second, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Then<'i, Input: 'i>: Sized {
|
||||
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input>
|
||||
where
|
||||
|
@ -44,6 +77,19 @@ pub trait Then<'i, Input: 'i>: Sized {
|
|||
|
||||
impl<'i, First: Node<'i, Input>, Input: 'i> Then<'i, Input> for First {}
|
||||
|
||||
pub trait AndThen<'i, Input: 'i>: Sized {
|
||||
fn and_then<Second>(self, second: Second) -> AsyncComposeNode<Self, Second, Input>
|
||||
where
|
||||
Self: Node<'i, Input>,
|
||||
Self::Output: core::future::Future,
|
||||
Second: Node<'i, <<Self as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
|
||||
{
|
||||
AsyncComposeNode::new(self, second)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, First: Node<'i, Input>, Input: 'i> AndThen<'i, Input> for First {}
|
||||
|
||||
pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>);
|
||||
|
||||
impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root>
|
||||
|
|
|
@ -15,7 +15,7 @@ pub struct TextGenerator<Text, FontName, Size> {
|
|||
}
|
||||
|
||||
#[node_fn(TextGenerator)]
|
||||
fn generate_text<'a: 'input>(editor: EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
||||
fn generate_text<'a: 'input>(editor: &'a EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
||||
let buzz_face = editor.font_cache.and_then(|cache| cache.get(&font_name)).map(|data| load_face(data));
|
||||
crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None))
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ mod test {
|
|||
assert_eq!(node.eval(()), 0);
|
||||
}
|
||||
#[test]
|
||||
#[allow(clippy::unit_cmp)]
|
||||
fn test_unit_node() {
|
||||
let node = ForgetNode::new();
|
||||
assert_eq!(node.eval(()), ());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue