mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Add the GPoll evaluation vocabulary and an inert Type::Ref variant
This commit is contained in:
@@ -323,6 +323,7 @@ pub(crate) fn property_from_type(
|
||||
Type::Generic(_) => vec![TextLabel::new("Generic Type (Not Supported)").widget_instance()].into(),
|
||||
Type::Fn(_, out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, context),
|
||||
Type::Future(out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, context),
|
||||
Type::Ref(inner) => return property_from_type(node_id, index, inner, number_options, unit, display_decimal_places, step, context),
|
||||
};
|
||||
|
||||
extra_widgets.push(widgets);
|
||||
|
||||
@@ -309,6 +309,7 @@ macro_rules! tagged_value {
|
||||
pub fn from_type(input: &Type) -> Option<Self> {
|
||||
match input {
|
||||
Type::Generic(_) => None,
|
||||
Type::Ref(_) => None,
|
||||
Type::Concrete(concrete_type) => {
|
||||
let name = concrete_type.name.as_ref();
|
||||
// TODO: Add default implementations for types such as TaggedValue::Subpaths, and use the defaults here and in document_node_types
|
||||
@@ -569,6 +570,7 @@ impl TaggedValue {
|
||||
|
||||
match ty {
|
||||
Type::Generic(_) => None,
|
||||
Type::Ref(_) => None,
|
||||
Type::Concrete(concrete_type) => {
|
||||
let ty = concrete_type.id?;
|
||||
use std::any::TypeId;
|
||||
|
||||
222
node-graph/libraries/core-types/src/gpoll.rs
Normal file
222
node-graph/libraries/core-types/src/gpoll.rs
Normal file
@@ -0,0 +1,222 @@
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ErrorKind {
|
||||
Node(&'static str),
|
||||
ArenaExhausted,
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for ErrorKind {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
matches!(self, ErrorKind::Node(kind) if kind == other)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct GraphError {
|
||||
pub kind: ErrorKind,
|
||||
pub trace: Vec<usize>,
|
||||
}
|
||||
|
||||
impl GraphError {
|
||||
pub fn new(kind: &'static str) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::Node(kind),
|
||||
trace: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum GPoll<T> {
|
||||
Pending,
|
||||
Final(T),
|
||||
Partial(T),
|
||||
Fallback(Box<(T, GraphError)>),
|
||||
Error(Box<GraphError>),
|
||||
}
|
||||
|
||||
impl<T> GPoll<T> {
|
||||
#[inline(always)]
|
||||
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> GPoll<U> {
|
||||
match self {
|
||||
GPoll::Pending => GPoll::Pending,
|
||||
GPoll::Final(value) => GPoll::Final(f(value)),
|
||||
GPoll::Partial(value) => GPoll::Partial(f(value)),
|
||||
GPoll::Fallback(boxed) => {
|
||||
let (value, e) = *boxed;
|
||||
GPoll::Fallback(Box::new((f(value), e)))
|
||||
}
|
||||
GPoll::Error(e) => GPoll::Error(e),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn and_then<U>(self, f: impl FnOnce(T) -> GPoll<U>) -> GPoll<U> {
|
||||
match self {
|
||||
GPoll::Pending => GPoll::Pending,
|
||||
GPoll::Final(value) => f(value),
|
||||
GPoll::Partial(value) => match f(value) {
|
||||
GPoll::Final(result) => GPoll::Partial(result),
|
||||
other => other,
|
||||
},
|
||||
GPoll::Fallback(boxed) => {
|
||||
let (value, e) = *boxed;
|
||||
match f(value) {
|
||||
GPoll::Pending => GPoll::Pending,
|
||||
GPoll::Final(result) | GPoll::Partial(result) => GPoll::Fallback(Box::new((result, e))),
|
||||
GPoll::Fallback(inner) => {
|
||||
let (result, _) = *inner;
|
||||
GPoll::Fallback(Box::new((result, e)))
|
||||
}
|
||||
GPoll::Error(inner) => GPoll::Error(inner),
|
||||
}
|
||||
}
|
||||
GPoll::Error(e) => GPoll::Error(e),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn zip<U>(self, other: GPoll<U>) -> GPoll<(T, U)> {
|
||||
match (self, other) {
|
||||
(GPoll::Error(e), _) | (_, GPoll::Error(e)) => GPoll::Error(e),
|
||||
(GPoll::Pending, _) | (_, GPoll::Pending) => GPoll::Pending,
|
||||
(GPoll::Final(a), GPoll::Final(b)) => GPoll::Final((a, b)),
|
||||
(GPoll::Fallback(boxed), GPoll::Final(b) | GPoll::Partial(b)) => {
|
||||
let (a, e) = *boxed;
|
||||
GPoll::Fallback(Box::new(((a, b), e)))
|
||||
}
|
||||
(GPoll::Final(a) | GPoll::Partial(a), GPoll::Fallback(boxed)) => {
|
||||
let (b, e) = *boxed;
|
||||
GPoll::Fallback(Box::new(((a, b), e)))
|
||||
}
|
||||
(GPoll::Fallback(first), GPoll::Fallback(second)) => {
|
||||
let (a, e) = *first;
|
||||
let (b, _) = *second;
|
||||
GPoll::Fallback(Box::new(((a, b), e)))
|
||||
}
|
||||
(GPoll::Partial(a), GPoll::Final(b) | GPoll::Partial(b)) | (GPoll::Final(a), GPoll::Partial(b)) => GPoll::Partial((a, b)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn trace(self, input: usize) -> Self {
|
||||
match self {
|
||||
GPoll::Fallback(mut boxed) => {
|
||||
boxed.1.trace.push(input);
|
||||
GPoll::Fallback(boxed)
|
||||
}
|
||||
GPoll::Error(mut e) => {
|
||||
e.trace.push(input);
|
||||
GPoll::Error(e)
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fallback(value: T, kind: &'static str) -> Self {
|
||||
GPoll::Fallback(Box::new((value, GraphError::new(kind))))
|
||||
}
|
||||
|
||||
pub fn error(kind: &'static str) -> Self {
|
||||
GPoll::Error(Box::new(GraphError::new(kind)))
|
||||
}
|
||||
|
||||
pub fn arena_exhausted() -> Self {
|
||||
GPoll::Error(Box::new(GraphError {
|
||||
kind: ErrorKind::ArenaExhausted,
|
||||
trace: Vec::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Interrupt {
|
||||
Pending,
|
||||
Error(Box<GraphError>),
|
||||
}
|
||||
|
||||
impl From<GraphError> for Interrupt {
|
||||
fn from(error: GraphError) -> Self {
|
||||
Interrupt::Error(Box::new(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Interrupt> for GPoll<T> {
|
||||
fn from(interrupt: Interrupt) -> Self {
|
||||
match interrupt {
|
||||
Interrupt::Pending => GPoll::Pending,
|
||||
Interrupt::Error(e) => GPoll::Error(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Extent {
|
||||
Free,
|
||||
Exactly(usize),
|
||||
}
|
||||
|
||||
impl Extent {
|
||||
pub fn meet(a: GPoll<Extent>, b: GPoll<Extent>) -> GPoll<Extent> {
|
||||
a.zip(b).and_then(|(a, b)| match (a, b) {
|
||||
(Extent::Free, other) | (other, Extent::Free) => GPoll::Final(other),
|
||||
(Extent::Exactly(n), Extent::Exactly(m)) if n == m => GPoll::Final(Extent::Exactly(n)),
|
||||
(Extent::Exactly(n), Extent::Exactly(m)) => GPoll::fallback(Extent::Exactly(n.min(m)), "extent mismatch"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Finality {
|
||||
AllFinal,
|
||||
Partial,
|
||||
}
|
||||
|
||||
impl Finality {
|
||||
pub fn meet(self, other: Finality) -> Finality {
|
||||
match (self, other) {
|
||||
(Finality::AllFinal, Finality::AllFinal) => Finality::AllFinal,
|
||||
_ => Finality::Partial,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn free_is_the_meet_identity() {
|
||||
let meet = Extent::meet(GPoll::Final(Extent::Free), GPoll::Final(Extent::Exactly(4)));
|
||||
assert_eq!(meet, GPoll::Final(Extent::Exactly(4)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extent_mismatch_truncates_and_reports() {
|
||||
let meet = Extent::meet(GPoll::Final(Extent::Exactly(3)), GPoll::Final(Extent::Exactly(5)));
|
||||
let GPoll::Fallback(boxed) = meet else {
|
||||
panic!("expected fallback, got {meet:?}");
|
||||
};
|
||||
assert_eq!(boxed.0, Extent::Exactly(3));
|
||||
assert!(boxed.1.kind == "extent mismatch");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_dominates_pending_in_zip() {
|
||||
let zipped = GPoll::<u32>::error("boom").zip(GPoll::<u32>::Pending);
|
||||
assert!(matches!(zipped, GPoll::Error(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_builds_root_to_source_path() {
|
||||
let poll = GPoll::<u32>::error("boom").trace(2).trace(0);
|
||||
let GPoll::Error(e) = poll else { unreachable!() };
|
||||
assert_eq!(e.trace, vec![2, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interrupt_round_trips_to_gpoll() {
|
||||
assert_eq!(GPoll::<u32>::from(Interrupt::Pending), GPoll::Pending);
|
||||
let interrupt = Interrupt::from(GraphError::new("boom"));
|
||||
assert!(matches!(GPoll::<u32>::from(interrupt), GPoll::Error(e) if e.kind == "boom"));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ pub mod bounds;
|
||||
pub mod consts;
|
||||
pub mod context;
|
||||
pub mod generic;
|
||||
pub mod gpoll;
|
||||
pub mod list;
|
||||
pub mod math;
|
||||
pub mod memo;
|
||||
|
||||
@@ -235,6 +235,7 @@ pub enum Type {
|
||||
Fn(Box<Type>, Box<Type>),
|
||||
/// Represents a future which promises to return the inner type.
|
||||
Future(Box<Type>),
|
||||
Ref(Box<Type>),
|
||||
}
|
||||
|
||||
impl Default for Type {
|
||||
@@ -308,6 +309,7 @@ impl Type {
|
||||
Self::Concrete(ty) => Some(ty.size),
|
||||
Self::Fn(_, _) => None,
|
||||
Self::Future(_) => None,
|
||||
Self::Ref(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +319,7 @@ impl Type {
|
||||
Self::Concrete(ty) => Some(ty.align),
|
||||
Self::Fn(_, _) => None,
|
||||
Self::Future(_) => None,
|
||||
Self::Ref(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +329,7 @@ impl Type {
|
||||
Self::Concrete(_) => self,
|
||||
Self::Fn(_, output) => output.nested_type(),
|
||||
Self::Future(output) => output.nested_type(),
|
||||
Self::Ref(inner) => inner.nested_type(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,6 +342,7 @@ impl Type {
|
||||
Self::Concrete(_) => None,
|
||||
Self::Fn(_, output) => output.replace_nested(f),
|
||||
Self::Future(output) => output.replace_nested(f),
|
||||
Self::Ref(inner) => inner.replace_nested(f),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,6 +352,7 @@ impl Type {
|
||||
Type::Concrete(ty) => simplify_identifier_name(&ty.name),
|
||||
Type::Fn(call_arg, return_value) => format!("{} called with {}", return_value.identifier_name(), call_arg.identifier_name()),
|
||||
Type::Future(ty) => ty.identifier_name(),
|
||||
Type::Ref(ty) => ty.identifier_name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,6 +447,7 @@ impl std::fmt::Display for Type {
|
||||
Type::Concrete(ty) => write!(f, "{ty}"),
|
||||
Type::Fn(_, return_value) => write!(f, "{return_value}"),
|
||||
Type::Future(ty) => write!(f, "{ty}"),
|
||||
Type::Ref(ty) => write!(f, "{ty}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user