mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
Restructure GPU execution to model GPU pipelines in the node graph (#1088)
* Start implementing GpuExecutor for wgpu * Implement read_output_buffer function * Implement extraction node in the compiler * Generate type annotations during shader compilation * Start adding node wrapprs for graph execution api * Wrap more of the api in nodes * Restructure Pipeline to accept arbitrary shader inputs * Adapt nodes to new trait definitions * Start implementing gpu-compiler trait * Adapt shader generation * Hardstuck on pointer casts * Pass nodes as references in gpu code to avoid zsts * Update gcore to compile on the gpu * Fix color doc tests * Impl Node for node refs
This commit is contained in:
committed by
Keavon Chambers
parent
161bbc62b4
commit
bdc1ef926a
@@ -1,4 +1,7 @@
|
||||
use crate::{raster::Sample, Color};
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use spirv_std::image::{Image2d, SampledImage};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Pod, Zeroable)]
|
||||
@@ -6,3 +9,12 @@ pub struct PushConstants {
|
||||
pub n: u32,
|
||||
pub node: u32,
|
||||
}
|
||||
|
||||
impl Sample for SampledImage<Image2d> {
|
||||
type Pixel = Color;
|
||||
|
||||
fn sample(&self, pos: glam::DVec2) -> Option<Self::Pixel> {
|
||||
let color = self.sample(pos);
|
||||
Color::from_rgbaf32(color.x, color.y, color.z, color.w)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ pub mod value;
|
||||
#[cfg(feature = "gpu")]
|
||||
pub mod gpu;
|
||||
|
||||
pub mod storage;
|
||||
|
||||
pub mod raster;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod transform;
|
||||
@@ -44,8 +46,8 @@ pub use types::*;
|
||||
|
||||
pub trait NodeIO<'i, Input: 'i>: 'i + Node<'i, Input>
|
||||
where
|
||||
Self::Output: 'i + StaticType,
|
||||
Input: 'i + StaticType,
|
||||
Self::Output: 'i + StaticTypeSized,
|
||||
Input: 'i + StaticTypeSized,
|
||||
{
|
||||
fn input_type(&self) -> TypeId {
|
||||
TypeId::of::<Input::Static>()
|
||||
@@ -54,7 +56,7 @@ where
|
||||
core::any::type_name::<Input>()
|
||||
}
|
||||
fn output_type(&self) -> core::any::TypeId {
|
||||
TypeId::of::<<Self::Output as StaticType>::Static>()
|
||||
TypeId::of::<<Self::Output as StaticTypeSized>::Static>()
|
||||
}
|
||||
fn output_type_name(&self) -> &'static str {
|
||||
core::any::type_name::<Self::Output>()
|
||||
@@ -62,8 +64,8 @@ where
|
||||
#[cfg(feature = "alloc")]
|
||||
fn to_node_io(&self, parameters: Vec<Type>) -> NodeIOTypes {
|
||||
NodeIOTypes {
|
||||
input: concrete!(<Input as StaticType>::Static),
|
||||
output: concrete!(<Self::Output as StaticType>::Static),
|
||||
input: concrete!(<Input as StaticTypeSized>::Static),
|
||||
output: concrete!(<Self::Output as StaticTypeSized>::Static),
|
||||
parameters,
|
||||
}
|
||||
}
|
||||
@@ -71,8 +73,8 @@ where
|
||||
|
||||
impl<'i, N: Node<'i, I>, I> NodeIO<'i, I> for N
|
||||
where
|
||||
N::Output: 'i + StaticType,
|
||||
I: 'i + StaticType,
|
||||
N::Output: 'i + StaticTypeSized,
|
||||
I: 'i + StaticTypeSized,
|
||||
{
|
||||
}
|
||||
|
||||
@@ -83,6 +85,13 @@ where
|
||||
(**self).eval(input)
|
||||
}
|
||||
}*/
|
||||
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for &'s N {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn for<'a> Node<'a, I, Output = O> {
|
||||
type Output = O;
|
||||
|
||||
@@ -92,7 +101,7 @@ impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn for<'a> Node<'a, I, Output = O> {
|
||||
}
|
||||
use core::pin::Pin;
|
||||
|
||||
use dyn_any::StaticType;
|
||||
use dyn_any::StaticTypeSized;
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<Box<dyn for<'a> Node<'a, I, Output = O> + 'i>> {
|
||||
type Output = O;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::Add;
|
||||
use core::ops::{Add, Mul};
|
||||
|
||||
use crate::Node;
|
||||
|
||||
@@ -30,6 +30,27 @@ where
|
||||
first + second
|
||||
}
|
||||
|
||||
pub struct MulParameterNode<Second> {
|
||||
second: Second,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(MulParameterNode)]
|
||||
fn flat_map<U, T>(first: U, second: T) -> <U as Mul<T>>::Output
|
||||
where
|
||||
U: Mul<T>,
|
||||
{
|
||||
first * second
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
struct SizeOfNode {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[node_macro::node_fn(SizeOfNode)]
|
||||
fn flat_map(ty: crate::Type) -> Option<usize> {
|
||||
ty.size()
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct SomeNode;
|
||||
#[node_macro::node_fn(SomeNode)]
|
||||
|
||||
@@ -2,6 +2,9 @@ use crate::raster::Color;
|
||||
use crate::Node;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
|
||||
#[cfg(target_arch = "spirv")]
|
||||
use spirv_std::num_traits::Float;
|
||||
|
||||
#[derive(Clone, Debug, DynAny, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Quantization {
|
||||
|
||||
@@ -4,50 +4,52 @@ use crate::Node;
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use glam::DVec2;
|
||||
use num::Num;
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
use num_traits::{cast::cast as num_cast, Num, NumCast};
|
||||
#[cfg(target_arch = "spirv")]
|
||||
use spirv_std::num_traits::float::Float;
|
||||
use spirv_std::num_traits::{cast::cast as num_cast, float::Float, FromPrimitive, Num, NumCast, ToPrimitive};
|
||||
|
||||
pub use self::color::Color;
|
||||
|
||||
pub mod adjustments;
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
pub mod brightness_contrast;
|
||||
pub mod color;
|
||||
pub use adjustments::*;
|
||||
|
||||
pub trait Channel: Copy + Debug + num::Num + num::NumCast {
|
||||
pub trait Channel: Copy + Debug + Num + NumCast {
|
||||
fn to_linear<Out: Linear>(self) -> Out;
|
||||
fn from_linear<In: Linear>(linear: In) -> Self;
|
||||
fn to_f32(self) -> f32 {
|
||||
num::cast(self).expect("Failed to convert channel to f32")
|
||||
num_cast(self).expect("Failed to convert channel to f32")
|
||||
}
|
||||
fn from_f32(value: f32) -> Self {
|
||||
num::cast(value).expect("Failed to convert f32 to channel")
|
||||
num_cast(value).expect("Failed to convert f32 to channel")
|
||||
}
|
||||
fn to_f64(self) -> f64 {
|
||||
num::cast(self).expect("Failed to convert channel to f64")
|
||||
num_cast(self).expect("Failed to convert channel to f64")
|
||||
}
|
||||
fn from_f64(value: f64) -> Self {
|
||||
num::cast(value).expect("Failed to convert f64 to channel")
|
||||
num_cast(value).expect("Failed to convert f64 to channel")
|
||||
}
|
||||
fn to_channel<Out: Channel>(self) -> Out {
|
||||
num::cast(self).expect("Failed to convert channel to channel")
|
||||
num_cast(self).expect("Failed to convert channel to channel")
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Linear: num::NumCast + Num {}
|
||||
pub trait Linear: NumCast + Num {}
|
||||
impl Linear for f32 {}
|
||||
impl Linear for f64 {}
|
||||
|
||||
impl<T: Linear + Debug + Copy> Channel for T {
|
||||
#[inline(always)]
|
||||
fn to_linear<Out: Linear>(self) -> Out {
|
||||
num::cast(self).expect("Failed to convert channel to linear")
|
||||
num_cast(self).expect("Failed to convert channel to linear")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_linear<In: Linear>(linear: In) -> Self {
|
||||
num::cast(linear).expect("Failed to convert linear to channel")
|
||||
num_cast(linear).expect("Failed to convert linear to channel")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,16 +60,16 @@ struct SRGBGammaFloat(f32);
|
||||
impl Channel for SRGBGammaFloat {
|
||||
#[inline(always)]
|
||||
fn to_linear<Out: Linear>(self) -> Out {
|
||||
let channel = num::cast::<_, f32>(self).expect("Failed to convert srgb to linear");
|
||||
let channel = num_cast::<_, f32>(self).expect("Failed to convert srgb to linear");
|
||||
let out = if channel <= 0.04045 { channel / 12.92 } else { ((channel + 0.055) / 1.055).powf(2.4) };
|
||||
num::cast(out).expect("Failed to convert srgb to linear")
|
||||
num_cast(out).expect("Failed to convert srgb to linear")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_linear<In: Linear>(linear: In) -> Self {
|
||||
let linear = num::cast::<_, f32>(linear).expect("Failed to convert linear to srgb");
|
||||
let linear = num_cast::<_, f32>(linear).expect("Failed to convert linear to srgb");
|
||||
let out = if linear <= 0.0031308 { linear * 12.92 } else { 1.055 * linear.powf(1. / 2.4) - 0.055 };
|
||||
num::cast(out).expect("Failed to convert linear to srgb")
|
||||
num_cast(out).expect("Failed to convert linear to srgb")
|
||||
}
|
||||
}
|
||||
pub trait RGBPrimaries {
|
||||
@@ -98,6 +100,7 @@ impl<T> Serde for T {}
|
||||
|
||||
// TODO: Come up with a better name for this trait
|
||||
pub trait Pixel: Clone + Pod + Zeroable {
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
bytemuck::bytes_of(self).to_vec()
|
||||
}
|
||||
@@ -107,7 +110,7 @@ pub trait Pixel: Clone + Pod + Zeroable {
|
||||
}
|
||||
|
||||
fn byte_size() -> usize {
|
||||
std::mem::size_of::<Self>()
|
||||
core::mem::size_of::<Self>()
|
||||
}
|
||||
}
|
||||
pub trait RGB: Pixel {
|
||||
@@ -448,6 +451,8 @@ pub struct ImageSlice<'a, Pixel> {
|
||||
pub data: &'a [Pixel],
|
||||
#[cfg(target_arch = "spirv")]
|
||||
pub data: &'a (),
|
||||
#[cfg(target_arch = "spirv")]
|
||||
pub _marker: PhantomData<Pixel>,
|
||||
}
|
||||
|
||||
unsafe impl<P: StaticTypeSized> StaticType for ImageSlice<'_, P> {
|
||||
@@ -470,20 +475,17 @@ impl<'a, P> Default for ImageSlice<'a, P> {
|
||||
width: Default::default(),
|
||||
height: Default::default(),
|
||||
data: &NOTHING,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
impl<P: Copy + Debug + Pixel> Raster for ImageSlice<'_, P> {
|
||||
type Pixel = P;
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
fn get_pixel(&self, x: u32, y: u32) -> Option<P> {
|
||||
self.data.get((x + y * self.width) as usize).copied()
|
||||
}
|
||||
#[cfg(target_arch = "spirv")]
|
||||
fn get_pixel(&self, _x: u32, _y: u32) -> P {
|
||||
Color::default()
|
||||
}
|
||||
fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
@@ -605,6 +607,8 @@ mod image {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Evaluate if this will be a problem for our use case.
|
||||
/// Warning: This is an approximation of a hash, and is not guaranteed to not collide.
|
||||
impl<P: Hash + Pixel> Hash for Image<P> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
const HASH_SAMPLES: u64 = 1000;
|
||||
@@ -661,7 +665,7 @@ mod image {
|
||||
let Image { width, height, data } = self;
|
||||
|
||||
let to_gamma = |x| SRGBGammaFloat::from_linear(x);
|
||||
let to_u8 = |x| (num::cast::<_, f32>(x).unwrap() * 255.) as u8;
|
||||
let to_u8 = |x| (num_cast::<_, f32>(x).unwrap() * 255.) as u8;
|
||||
|
||||
let result_bytes = data
|
||||
.into_iter()
|
||||
@@ -670,7 +674,7 @@ mod image {
|
||||
to_u8(to_gamma(color.r() / color.a().to_channel())),
|
||||
to_u8(to_gamma(color.g() / color.a().to_channel())),
|
||||
to_u8(to_gamma(color.b() / color.a().to_channel())),
|
||||
(num::cast::<_, f32>(color.a()).unwrap() * 255.) as u8,
|
||||
(num_cast::<_, f32>(color.a()).unwrap() * 255.) as u8,
|
||||
]
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::Node;
|
||||
|
||||
use core::fmt::Debug;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(target_arch = "spirv")]
|
||||
@@ -457,8 +458,9 @@ fn vibrance_node(color: Color, vibrance: f64) -> Color {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, DynAny, specta::Type)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "std", derive(specta::Type))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)]
|
||||
pub enum RedGreenBlue {
|
||||
Red,
|
||||
Green,
|
||||
@@ -542,8 +544,9 @@ fn channel_mixer_node(
|
||||
color.to_linear_srgb()
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, DynAny, specta::Type)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "std", derive(specta::Type))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)]
|
||||
pub enum RelativeAbsolute {
|
||||
Relative,
|
||||
Absolute,
|
||||
@@ -559,7 +562,9 @@ impl core::fmt::Display for RelativeAbsolute {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, DynAny, specta::Type)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "std", derive(specta::Type))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)]
|
||||
pub enum SelectiveColorChoice {
|
||||
Reds,
|
||||
Yellows,
|
||||
@@ -797,17 +802,26 @@ fn exposure(color: Color, exposure: f64, offset: f64, gamma_correction: f64) ->
|
||||
adjusted.map_rgb(|c: f32| c.clamp(0., 1.))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IndexNode<Index> {
|
||||
pub index: Index,
|
||||
}
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use index_node::IndexNode;
|
||||
|
||||
#[node_macro::node_fn(IndexNode)]
|
||||
pub fn index_node(input: Vec<super::ImageFrame<Color>>, index: u32) -> super::ImageFrame<Color> {
|
||||
if (index as usize) < input.len() {
|
||||
input[index as usize].clone()
|
||||
} else {
|
||||
warn!("The number of segments is {} and the requested segment is {}!", input.len(), index);
|
||||
super::ImageFrame::empty()
|
||||
#[cfg(feature = "alloc")]
|
||||
mod index_node {
|
||||
use crate::raster::{Color, ImageFrame};
|
||||
use crate::Node;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IndexNode<Index> {
|
||||
pub index: Index,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(IndexNode)]
|
||||
pub fn index_node(input: Vec<ImageFrame<Color>>, index: u32) -> ImageFrame<Color> {
|
||||
if (index as usize) < input.len() {
|
||||
input[index as usize].clone()
|
||||
} else {
|
||||
warn!("The number of segments is {} and the requested segment is {}!", input.len(), index);
|
||||
ImageFrame::empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ fn brightness_contrast_legacy_node(_primary: (), brightness: f32, contrast: f32)
|
||||
let brightness = brightness / 255.;
|
||||
|
||||
let contrast = contrast / 100.;
|
||||
let contrast = if contrast > 0. { (contrast * std::f32::consts::FRAC_PI_2 - 0.01).tan() } else { contrast };
|
||||
let contrast = if contrast > 0. { (contrast * core::f32::consts::FRAC_PI_2 - 0.01).tan() } else { contrast };
|
||||
|
||||
let combined = brightness * contrast + brightness - contrast / 2.;
|
||||
|
||||
@@ -172,7 +172,7 @@ fn solve_cubic_splines(cubic_spline_values: &CubicSplines) -> [f32; 4] {
|
||||
|
||||
// Eliminate the current column in all rows below the current one
|
||||
for row_below_current in row + 1..4 {
|
||||
assert!(augmented_matrix[row][row].abs() > std::f32::EPSILON);
|
||||
assert!(augmented_matrix[row][row].abs() > core::f32::EPSILON);
|
||||
|
||||
let scale_factor = augmented_matrix[row_below_current][row] / augmented_matrix[row][row];
|
||||
for col in row..5 {
|
||||
@@ -184,7 +184,7 @@ fn solve_cubic_splines(cubic_spline_values: &CubicSplines) -> [f32; 4] {
|
||||
// Gaussian elimination: back substitution
|
||||
let mut solutions = [0.; 4];
|
||||
for col in (0..4).rev() {
|
||||
assert!(augmented_matrix[col][col].abs() > std::f32::EPSILON);
|
||||
assert!(augmented_matrix[col][col].abs() > core::f32::EPSILON);
|
||||
|
||||
solutions[col] = augmented_matrix[col][4] / augmented_matrix[col][col];
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ impl RGB for Color {
|
||||
}
|
||||
|
||||
impl Pixel for Color {
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
self.to_rgba8_srgb().to_vec()
|
||||
}
|
||||
@@ -121,7 +122,6 @@ impl Color {
|
||||
/// let color = Color::from_rgbaf32(1.0, 1.0, 1.0, f32::NAN);
|
||||
/// assert!(color == None);
|
||||
/// ```
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
pub fn from_rgbaf32(red: f32, green: f32, blue: f32, alpha: f32) -> Option<Color> {
|
||||
if alpha > 1. || [red, green, blue, alpha].iter().any(|c| c.is_sign_negative() || !c.is_finite()) {
|
||||
return None;
|
||||
@@ -492,7 +492,7 @@ impl Color {
|
||||
/// ```
|
||||
/// use graphene_core::raster::color::Color;
|
||||
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
|
||||
/// assert!(color.components() == (0.114, 0.103, 0.98, 0.97));
|
||||
/// assert_eq!(color.components(), (0.114, 0.103, 0.98, 0.97));
|
||||
/// ```
|
||||
pub fn components(&self) -> (f32, f32, f32, f32) {
|
||||
(self.red, self.green, self.blue, self.alpha)
|
||||
@@ -585,7 +585,6 @@ impl Color {
|
||||
/// use graphene_core::raster::color::Color;
|
||||
/// let color = Color::from_rgba_str("7C67FA61").unwrap();
|
||||
/// ```
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
pub fn from_rgba_str(color_str: &str) -> Option<Color> {
|
||||
if color_str.len() != 8 {
|
||||
return None;
|
||||
@@ -603,7 +602,6 @@ impl Color {
|
||||
/// use graphene_core::raster::color::Color;
|
||||
/// let color = Color::from_rgb_str("7C67FA").unwrap();
|
||||
/// ```
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
pub fn from_rgb_str(color_str: &str) -> Option<Color> {
|
||||
if color_str.len() != 6 {
|
||||
return None;
|
||||
|
||||
34
node-graph/gcore/src/storage.rs
Normal file
34
node-graph/gcore/src/storage.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use crate::Node;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{DerefMut, Index, IndexMut};
|
||||
|
||||
struct SetNode<S, I, Storage, Index> {
|
||||
storage: Storage,
|
||||
index: Index,
|
||||
_s: PhantomData<S>,
|
||||
_i: PhantomData<I>,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(SetNode<_S, _I>)]
|
||||
fn set_node<T, _S, _I>(value: T, storage: &'any_input mut _S, index: _I)
|
||||
where
|
||||
_S: IndexMut<_I>,
|
||||
_S::Output: DerefMut<Target = T> + Sized,
|
||||
{
|
||||
*storage.index_mut(index).deref_mut() = value;
|
||||
}
|
||||
|
||||
struct GetNode<S, Storage> {
|
||||
storage: Storage,
|
||||
_s: PhantomData<S>,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(GetNode<_S>)]
|
||||
fn get_node<_S, I>(index: I, storage: &'any_input _S) -> &'input _S::Output
|
||||
where
|
||||
_S: Index<I>,
|
||||
_S::Output: Sized,
|
||||
{
|
||||
storage.index(index)
|
||||
}
|
||||
@@ -2,60 +2,47 @@ use core::marker::PhantomData;
|
||||
|
||||
use crate::Node;
|
||||
|
||||
pub struct ComposeNode<First: for<'i> Node<'i, I>, Second: for<'i> Node<'i, <First as Node<'i, I>>::Output>, I> {
|
||||
#[derive(Clone)]
|
||||
pub struct ComposeNode<First, Second, I> {
|
||||
first: First,
|
||||
second: Second,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<'i, Input: 'i, First, Second> Node<'i, Input> for ComposeNode<First, Second, Input>
|
||||
impl<'i, 'f: 'i, 's: 'i, Input: 'i, First, Second> Node<'i, Input> for ComposeNode<First, Second, Input>
|
||||
where
|
||||
First: for<'a> Node<'a, Input> + 'i,
|
||||
Second: for<'a> Node<'a, <First as Node<'a, Input>>::Output> + 'i,
|
||||
First: Node<'i, Input>,
|
||||
Second: Node<'i, <First as Node<'i, Input>>::Output> + 'i,
|
||||
{
|
||||
type Output = <Second as Node<'i, <First as Node<'i, Input>>::Output>>::Output;
|
||||
fn eval(&'i self, input: Input) -> Self::Output {
|
||||
let arg = self.first.eval(input);
|
||||
self.second.eval(arg)
|
||||
let second = &self.second;
|
||||
second.eval(arg)
|
||||
}
|
||||
}
|
||||
|
||||
impl<First, Second, Input> ComposeNode<First, Second, Input>
|
||||
impl<'i, First, Second, Input: 'i> ComposeNode<First, Second, Input>
|
||||
where
|
||||
First: for<'a> Node<'a, Input>,
|
||||
Second: for<'a> Node<'a, <First as Node<'a, Input>>::Output>,
|
||||
First: Node<'i, Input>,
|
||||
Second: Node<'i, <First as Node<'i, Input>>::Output>,
|
||||
{
|
||||
pub const fn new(first: First, second: Second) -> Self {
|
||||
ComposeNode::<First, Second, Input> { first, second, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
// impl Clone for ComposeNode<First, Second, Input>
|
||||
impl<First, Second, Input> Clone for ComposeNode<First, Second, Input>
|
||||
where
|
||||
First: for<'a> Node<'a, Input> + Clone,
|
||||
Second: for<'a> Node<'a, <First as Node<'a, Input>>::Output> + Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
ComposeNode::<First, Second, Input> {
|
||||
first: self.first.clone(),
|
||||
second: self.second.clone(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Then<'i, Input: 'i>: Sized {
|
||||
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input>
|
||||
where
|
||||
Self: for<'a> Node<'a, Input>,
|
||||
Second: for<'a> Node<'a, <Self as Node<'a, Input>>::Output>,
|
||||
Self: Node<'i, Input>,
|
||||
Second: Node<'i, <Self as Node<'i, Input>>::Output>,
|
||||
{
|
||||
ComposeNode::new(self, second)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, First: for<'a> Node<'a, Input>, Input: 'i> Then<'i, Input> for First {}
|
||||
impl<'i, First: Node<'i, Input>, Input: 'i> Then<'i, Input> for First {}
|
||||
|
||||
pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>);
|
||||
|
||||
@@ -89,4 +76,16 @@ mod test {
|
||||
let type_erased = &compose as &dyn for<'i> Node<'i, (), Output = &'i u32>;
|
||||
assert_eq!(type_erased.eval(()), &4u32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ref_eval() {
|
||||
let value = ValueNode::new(5);
|
||||
|
||||
assert_eq!((&value).eval(()), &5);
|
||||
let id = IdNode::new();
|
||||
|
||||
let compose = ComposeNode::new(&value, &id);
|
||||
|
||||
assert_eq!(compose.eval(()), &5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use core::any::TypeId;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use alloc::borrow::Cow;
|
||||
use dyn_any::StaticType;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::borrow::Cow;
|
||||
|
||||
@@ -28,6 +29,8 @@ macro_rules! concrete {
|
||||
Type::Concrete(TypeDescriptor {
|
||||
id: Some(core::any::TypeId::of::<$type>()),
|
||||
name: Cow::Borrowed(core::any::type_name::<$type>()),
|
||||
size: core::mem::size_of::<$type>(),
|
||||
align: core::mem::align_of::<$type>(),
|
||||
})
|
||||
};
|
||||
}
|
||||
@@ -65,6 +68,8 @@ pub struct TypeDescriptor {
|
||||
#[specta(skip)]
|
||||
pub id: Option<TypeId>,
|
||||
pub name: Cow<'static, str>,
|
||||
pub size: usize,
|
||||
pub align: usize,
|
||||
}
|
||||
|
||||
impl core::hash::Hash for TypeDescriptor {
|
||||
@@ -137,6 +142,32 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn new<T: StaticType + Sized>() -> Self {
|
||||
Self::Concrete(TypeDescriptor {
|
||||
id: Some(TypeId::of::<T::Static>()),
|
||||
name: Cow::Borrowed(core::any::type_name::<T::Static>()),
|
||||
size: core::mem::size_of::<T>(),
|
||||
align: core::mem::align_of::<T>(),
|
||||
})
|
||||
}
|
||||
pub fn size(&self) -> Option<usize> {
|
||||
match self {
|
||||
Self::Generic(_) => None,
|
||||
Self::Concrete(ty) => Some(ty.size),
|
||||
Self::Fn(_, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align(&self) -> Option<usize> {
|
||||
match self {
|
||||
Self::Generic(_) => None,
|
||||
Self::Concrete(ty) => Some(ty.align),
|
||||
Self::Fn(_, _) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Type {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
|
||||
@@ -40,7 +40,7 @@ impl<T: Clone> Clone for ValueNode<T> {
|
||||
}
|
||||
impl<T: Clone + Copy> Copy for ValueNode<T> {}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ClonedNode<T: Clone>(pub T);
|
||||
|
||||
impl<'i, T: Clone + 'i> Node<'i, ()> for ClonedNode<T> {
|
||||
@@ -61,7 +61,22 @@ impl<T: Clone> From<T> for ClonedNode<T> {
|
||||
ClonedNode::new(value)
|
||||
}
|
||||
}
|
||||
impl<T: Clone + Copy> Copy for ClonedNode<T> {}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CopiedNode<T: Copy>(pub T);
|
||||
|
||||
impl<'i, T: Copy + 'i> Node<'i, ()> for CopiedNode<T> {
|
||||
type Output = T;
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> CopiedNode<T> {
|
||||
pub const fn new(value: T) -> CopiedNode<T> {
|
||||
CopiedNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DefaultNode<T>(PhantomData<T>);
|
||||
|
||||
Reference in New Issue
Block a user