From 94fbb8f88d7120804fe063e22d077b8b185eeb29 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 8 May 2024 08:31:31 +0100 Subject: [PATCH] implement CustomConst serialisation --- hugr-py/src/hugr/serialization/ops.py | 34 +-- hugr/src/ops/constant.rs | 62 +++- hugr/src/ops/constant/custom.rs | 280 +++++++++++++++++- .../schema/hugr_schema_strict_v1.json | 46 ++- specification/schema/hugr_schema_v1.json | 46 ++- .../schema/testing_hugr_schema_strict_v1.json | 46 ++- .../schema/testing_hugr_schema_v1.json | 46 ++- 7 files changed, 488 insertions(+), 72 deletions(-) diff --git a/hugr-py/src/hugr/serialization/ops.py b/hugr-py/src/hugr/serialization/ops.py index b818602b0..d722249a4 100644 --- a/hugr-py/src/hugr/serialization/ops.py +++ b/hugr-py/src/hugr/serialization/ops.py @@ -70,44 +70,33 @@ class FuncDecl(BaseOp): signature: PolyFuncType -CustomConst = Any # TODO +class CustomConst(ConfiguredBaseModel): + c: str + v: Any class ExtensionValue(ConfiguredBaseModel): """An extension constant value, that can check it is of a given [CustomType].""" - c: Literal["Extension"] = Field("Extension", title="ValueTag") - e: CustomConst = Field(title="CustomConst") - - class Config: - json_schema_extra = { - "required": ["c", "e"], - } + v: Literal["Extension"] = Field("Extension", title="ValueTag") + extensions: ExtensionSet + typ: Type + value: CustomConst class FunctionValue(ConfiguredBaseModel): """A higher-order function value.""" - c: Literal["Function"] = Field("Function", title="ValueTag") + v: Literal["Function"] = Field("Function", title="ValueTag") hugr: Any # TODO - class Config: - json_schema_extra = { - "required": ["c", "hugr"], - } - class TupleValue(ConfiguredBaseModel): """A constant tuple value.""" - c: Literal["Tuple"] = Field("Tuple", title="ValueTag") + v: Literal["Tuple"] = Field("Tuple", title="ValueTag") vs: list["Value"] - class Config: - json_schema_extra = { - "required": ["c", "vs"], - } - class SumValue(ConfiguredBaseModel): """A Sum variant @@ -115,7 +104,7 @@ class SumValue(ConfiguredBaseModel): For any Sum type where this value meets the type of the variant indicated by the tag """ - c: Literal["Sum"] = Field("Sum", title="ValueTag") + v: Literal["Sum"] = Field("Sum", title="ValueTag") tag: int typ: SumType vs: list["Value"] @@ -127,7 +116,6 @@ class Config: "A Sum variant For any Sum type where this value meets the type " "of the variant indicated by the tag." ), - "required": ["c", "tag", "typ", "vs"], } @@ -135,7 +123,7 @@ class Value(RootModel): """A constant Value.""" root: ExtensionValue | FunctionValue | TupleValue | SumValue = Field( - discriminator="c" + discriminator="v" ) diff --git a/hugr/src/ops/constant.rs b/hugr/src/ops/constant.rs index 01f9e46ea..297223f7f 100644 --- a/hugr/src/ops/constant.rs +++ b/hugr/src/ops/constant.rs @@ -10,6 +10,7 @@ use crate::{Hugr, HugrView}; use delegate::delegate; use itertools::Itertools; +use serde::{Deserializer, Serializer}; use smol_str::SmolStr; use thiserror::Error; @@ -91,12 +92,13 @@ impl AsRef for Const { } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -#[serde(tag = "c")] +#[serde(tag = "v")] /// A value that can be stored as a static constant. Representing core types and /// extension types. pub enum Value { /// An extension constant value, that can check it is of a given [CustomType]. Extension { + #[serde(flatten)] /// The custom constant value. e: ExtensionValue, }, @@ -133,21 +135,46 @@ pub enum Value { /// [`CustomConst`] are serialised through [`CustomSerialized`]. #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(transparent)] -pub struct ExtensionValue(Box); +pub struct ExtensionValue { + #[serde(serialize_with = "ExtensionValue::serialize_with")] + #[serde(deserialize_with = "ExtensionValue::deserialize_with")] + #[serde(flatten)] + v: Box, +} impl ExtensionValue { /// Create a new [`ExtensionValue`] from any [`CustomConst`]. pub fn new(cc: impl CustomConst) -> Self { - Self(Box::new(cc)) + Self { v: Box::new(cc) } } /// Returns a reference to the internal [`CustomConst`]. pub fn value(&self) -> &dyn CustomConst { - self.0.as_ref() + self.v.as_ref() + } + + fn deserialize_with<'de, D: Deserializer<'de>>( + deserializer: D, + ) -> Result, D::Error> { + use serde::Deserialize; + let cs = CustomSerialized::deserialize(deserializer)?; + Ok(cs.into()) + } + + fn serialize_with( + konst: impl AsRef, + serializer: S, + ) -> Result { + use serde::Serialize; + let cs: CustomSerialized = konst + .as_ref() + .try_into() + .map_err(::custom)?; + cs.serialize(serializer) } delegate! { - to self.0 { + to self.value() { /// Returns the type of the internal [`CustomConst`]. pub fn get_type(&self) -> Type; /// An identifier of the internal [`CustomConst`]. @@ -158,9 +185,15 @@ impl ExtensionValue { } } +impl From for ExtensionValue { + fn from(x: CC) -> Self { + Self::new(x) + } +} + impl PartialEq for ExtensionValue { fn eq(&self, other: &Self) -> bool { - self.0.equal_consts(other.0.as_ref()) + self.value().equal_consts(other.value()) } } @@ -304,14 +337,14 @@ impl Value { /// Returns a tuple constant of constant values. pub fn extension(custom_const: impl CustomConst) -> Self { Self::Extension { - e: ExtensionValue(Box::new(custom_const)), + e: ExtensionValue::new(custom_const), } } /// For a Const holding a CustomConst, extract the CustomConst by downcasting. pub fn get_custom_value(&self) -> Option<&T> { if let Self::Extension { e } = self { - e.0.downcast_ref() + e.v.downcast_ref() } else { None } @@ -411,12 +444,9 @@ mod test { /// A [`CustomSerialized`] encoding a [`FLOAT64_TYPE`] float constant used in testing. pub(crate) fn serialized_float(f: f64) -> Value { - CustomSerialized::new( - FLOAT64_TYPE, - serde_yaml::Value::Number(f.into()), - float_types::EXTENSION_ID, - ) - .into() + CustomSerialized::try_from_custom_const(ConstF64::new(f)) + .unwrap() + .into() } fn test_registry() -> ExtensionRegistry { @@ -438,7 +468,7 @@ mod test { 0, [ CustomTestValue(USIZE_CUSTOM_T).into(), - serialized_float(5.1), + ConstF64::new(5.1).into(), ], pred_ty.clone(), )?); @@ -523,7 +553,7 @@ mod test { #[rstest] #[case(Value::unit(), Type::UNIT, "const:seq:{}")] #[case(const_usize(), USIZE_T, "const:custom:ConstUsize(")] - #[case(serialized_float(17.4), FLOAT64_TYPE, "const:custom:yaml:Number(17.4)")] + // #[case(serialized_float(17.4), FLOAT64_TYPE, "const:custom:yaml:Number(17.4)")] #[case(const_tuple(), Type::new_tuple(type_row![USIZE_T, FLOAT64_TYPE]), "const:seq:{")] fn const_type( #[case] const_value: Value, diff --git a/hugr/src/ops/constant/custom.rs b/hugr/src/ops/constant/custom.rs index f5937028a..5815e4d1a 100644 --- a/hugr/src/ops/constant/custom.rs +++ b/hugr/src/ops/constant/custom.rs @@ -7,6 +7,7 @@ use std::any::Any; use downcast_rs::{impl_downcast, Downcast}; +use thiserror::Error; use crate::extension::ExtensionSet; use crate::macros::impl_box_clone; @@ -21,7 +22,7 @@ use super::ValueName; /// enable serialization. /// /// [`CustomType`]: crate::types::CustomType -#[typetag::serde(tag = "c")] +#[typetag::serde(tag = "c", content = "v")] pub trait CustomConst: Send + Sync + std::fmt::Debug + CustomConstBoxClone + Any + Downcast { @@ -70,6 +71,32 @@ pub fn downcast_equal_consts( } } +/// Serialize any CustomConst using the `impl Serialize for &dyn CustomConst`. +/// In particular this works on `&dyn CustomConst` and `Box::Target`. +/// See tests below +fn serialize_custom_const(cc: &dyn CustomConst) -> Result { + serde_yaml::to_value(cc) +} + +fn deserialize_custom_const( + value: serde_yaml::Value, +) -> Result { + match deserialize_dyn_custom_const(value)?.downcast::() { + Ok(cc) => Ok(*cc), + Err(dyn_cc) => Err(::custom(format!( + "Failed to deserialize [{}]: {:?}", + std::any::type_name::(), + dyn_cc + ))), + } +} + +fn deserialize_dyn_custom_const( + value: serde_yaml::Value, +) -> Result, serde_yaml::Error> { + serde_yaml::from_value(value) +} + impl_downcast!(CustomConst); impl_box_clone!(CustomConst, CustomConstBoxClone); @@ -81,6 +108,32 @@ pub struct CustomSerialized { extensions: ExtensionSet, } +#[derive(Debug, Error)] +pub enum CustomSerializedError { + #[error("Error serializing value into CustomSerialised: err: {err}, value: {payload:?}")] + SerializePayloadError { + #[source] + err: serde_yaml::Error, + payload: Box, + }, + #[error("Error serializing value into CustomSerialised: err: {err}, value: {payload:?}")] + DeserializePayloadError { + #[source] + err: serde_yaml::Error, + payload: serde_yaml::Value, + }, +} + +impl CustomSerializedError { + fn new_ser(err: serde_yaml::Error, payload: Box) -> Self { + Self::SerializePayloadError { err, payload } + } + + fn new_de(err: serde_yaml::Error, payload: serde_yaml::Value) -> Self { + Self::DeserializePayloadError { err, payload } + } +} + impl CustomSerialized { /// Creates a new [`CustomSerialized`]. pub fn new( @@ -99,6 +152,61 @@ impl CustomSerialized { pub fn value(&self) -> &serde_yaml::Value { &self.value } + + /// TODO + pub fn try_from_custom_const_ref( + cc: &(impl CustomConst + ?Sized), + ) -> Result { + Self::try_from_custom_const_box(cc.clone_box()) + } + + /// TODO + pub fn try_from_custom_const(cc: impl CustomConst) -> Result { + Self::try_from_custom_const_box(Box::new(cc)) + } + + /// TODO + pub fn try_from_custom_const_box( + cc: Box, + ) -> Result { + match cc.downcast::() { + Ok(x) => Ok(*x), + Err(cc) => { + let (typ, extension_reqs) = (cc.get_type(), cc.extension_reqs()); + let value = serialize_custom_const(cc.as_ref()) + .map_err(|err| CustomSerializedError::new_ser(err, cc))?; + Ok(Self::new(typ, value, extension_reqs)) + } + } + } + + /// TODO + pub fn into_custom_const_box(self) -> Box { + let (typ, extensions) = (self.get_type().clone(), self.extension_reqs()); + // ideally we would not have to clone, but serde_json does not allow us + // to recover the value from the error + let cc_box = + deserialize_dyn_custom_const(self.value.clone()).unwrap_or_else(|_| Box::new(self)); + assert_eq!(cc_box.get_type(), typ); + assert_eq!(cc_box.extension_reqs(), extensions); + cc_box + } + + /// TODO + pub fn try_into_custom_const(self) -> Result { + let CustomSerialized { + typ, + value, + extensions, + } = self; + // ideally we would not have to clone, but serde_json does not allow us + // to recover the value from the error + let cc: CC = deserialize_custom_const(value.clone()) + .map_err(|err| CustomSerializedError::new_de(err, value))?; + assert_eq!(cc.get_type(), typ); + assert_eq!(cc.extension_reqs(), extensions); + Ok(cc) + } } #[typetag::serde] @@ -118,3 +226,173 @@ impl CustomConst for CustomSerialized { self.typ.clone() } } + +impl TryFrom<&dyn CustomConst> for CustomSerialized { + type Error = CustomSerializedError; + fn try_from(value: &dyn CustomConst) -> Result { + Self::try_from_custom_const_ref(value) + } +} + +impl TryFrom> for CustomSerialized { + type Error = CustomSerializedError; + fn try_from(value: Box) -> Result { + Self::try_from_custom_const_box(value) + } +} + +impl From for Box { + fn from(cs: CustomSerialized) -> Self { + cs.into_custom_const_box() + } +} + +#[cfg(test)] +mod test { + + use rstest::rstest; + + use crate::{ + extension::{ + prelude::{ConstUsize, USIZE_T}, + ExtensionSet, + }, + ops::{ + constant::custom::{ + deserialize_dyn_custom_const, serialize_custom_const, + }, + Value, + }, + std_extensions::{arithmetic::int_types::ConstInt, collections::ListValue}, + }; + + use super::{CustomConst, CustomConstBoxClone, CustomSerialized}; + + struct SerializeCustomConstExample { + cc: CC, + tag: &'static str, + yaml: serde_yaml::Value, + } + + impl SerializeCustomConstExample { + fn new(cc: CC, tag: &'static str) -> Self { + let yaml = serde_yaml::to_value(&cc).unwrap(); + Self { cc, tag, yaml } + } + } + + fn ser_cc_ex1() -> SerializeCustomConstExample { + SerializeCustomConstExample::new(ConstUsize::new(12), "ConstUsize") + } + + fn ser_cc_ex2() -> SerializeCustomConstExample { + SerializeCustomConstExample::new( + ListValue::new( + USIZE_T, + [ConstUsize::new(1), ConstUsize::new(2)] + .into_iter() + .map(Value::extension), + ), + "ListValue", + ) + } + + fn ser_cc_ex3() -> SerializeCustomConstExample { + SerializeCustomConstExample::new( + CustomSerialized::new(USIZE_T, serde_yaml::Value::Null, ExtensionSet::default()), + "CustomSerialized", + ) + } + + #[rstest] + #[case(ser_cc_ex1())] + #[case(ser_cc_ex2())] + #[case(ser_cc_ex3())] + fn test_serialize_custom_const( + #[case] example: SerializeCustomConstExample, + ) { + let expected_yaml: serde_yaml::Value = + [("c".into(), example.tag.into()), ("v".into(), example.yaml)] + .into_iter() + .collect::() + .into(); + + let yaml_by_ref = serialize_custom_const(&example.cc as &CC).unwrap(); + assert_eq!(expected_yaml, yaml_by_ref); + + let yaml_by_dyn_ref = serialize_custom_const(&example.cc as &dyn CustomConst).unwrap(); + assert_eq!(expected_yaml, yaml_by_dyn_ref); + } + + #[test] + fn custom_serialized_from_into_custom_const() { + let const_int = ConstInt::new_s(4, 1).unwrap(); + + let cs: CustomSerialized = CustomSerialized::try_from_custom_const_ref(&const_int).unwrap(); + + assert_eq!(const_int.get_type(), cs.get_type()); + assert_eq!(const_int.extension_reqs(), cs.extension_reqs()); + assert_eq!(&serialize_custom_const(&const_int).unwrap(), cs.value()); + + let deser_const_int: ConstInt = cs.try_into_custom_const().unwrap(); + + assert_eq!(const_int, deser_const_int); + } + + #[test] + fn custom_serialized_from_into_custom_serialised() { + let const_int = ConstInt::new_s(4, 1).unwrap(); + let cs0: CustomSerialized = + CustomSerialized::try_from_custom_const_ref(&const_int).unwrap(); + + let cs1 = CustomSerialized::try_from_custom_const_ref(&cs0).unwrap(); + assert_eq!(&cs0, &cs1); + + let deser_const_int: ConstInt = cs0.try_into_custom_const().unwrap(); + assert_eq!(&const_int, &deser_const_int); + } + + #[test] + fn custom_serialized_try_from_dyn_custom_const() { + let const_int = ConstInt::new_s(4, 1).unwrap(); + let cs: CustomSerialized = const_int.clone_box().try_into().unwrap(); + assert_eq!(const_int.get_type(), cs.get_type()); + assert_eq!(const_int.extension_reqs(), cs.extension_reqs()); + assert_eq!(&serialize_custom_const(&const_int).unwrap(), cs.value()); + + let deser_const_int: ConstInt = { + let dyn_box: Box = cs.into(); + *dyn_box.downcast().unwrap() + }; + assert_eq!(const_int, deser_const_int) + } + + #[test] + fn nested_custom_serialized() { + let const_int = ConstInt::new_s(4, 1).unwrap(); + let cs_inner: CustomSerialized = + CustomSerialized::try_from_custom_const_ref(&const_int).unwrap(); + + let cs_inner_ser = serialize_custom_const(&cs_inner).unwrap(); + + // cs_outer is a CustomSerialized of a CustomSerialized of a ConstInt + let cs_outer = CustomSerialized::new( + cs_inner.get_type(), + cs_inner_ser.clone(), + cs_inner.extension_reqs(), + ); + // TODO should this be &const_int == cs_outer.value() ??? + assert_eq!(&cs_inner_ser, cs_outer.value()); + + assert_eq!(const_int.get_type(), cs_outer.get_type()); + assert_eq!(const_int.extension_reqs(), cs_outer.extension_reqs()); + + // TODO should this be &const_int = cs_outer.value() ??? + let inner_deser: Box = + deserialize_dyn_custom_const(cs_outer.value().clone()).unwrap(); + assert_eq!( + &cs_inner, + inner_deser.downcast_ref::().unwrap() + ); + } +} diff --git a/specification/schema/hugr_schema_strict_v1.json b/specification/schema/hugr_schema_strict_v1.json index 2ed6d0919..6dde15c17 100644 --- a/specification/schema/hugr_schema_strict_v1.json +++ b/specification/schema/hugr_schema_strict_v1.json @@ -498,6 +498,24 @@ "title": "Const", "type": "object" }, + "CustomConst": { + "additionalProperties": false, + "properties": { + "c": { + "title": "C", + "type": "string" + }, + "v": { + "title": "V" + } + }, + "required": [ + "c", + "v" + ], + "title": "CustomConst", + "type": "object" + }, "CustomOp": { "additionalProperties": false, "description": "A user-defined operation that can be downcasted by the extensions that define\nit.", @@ -725,7 +743,7 @@ "additionalProperties": false, "description": "An extension constant value, that can check it is of a given [CustomType].", "properties": { - "c": { + "v": { "const": "Extension", "default": "Extension", "enum": [ @@ -734,12 +752,24 @@ "title": "ValueTag", "type": "string" }, - "e": { - "title": "CustomConst" + "extensions": { + "items": { + "type": "string" + }, + "title": "Extensions", + "type": "array" + }, + "typ": { + "$ref": "#/$defs/Type" + }, + "value": { + "$ref": "#/$defs/CustomConst" } }, "required": [ - "e" + "extensions", + "typ", + "value" ], "title": "ExtensionValue", "type": "object" @@ -928,7 +958,7 @@ "additionalProperties": false, "description": "A higher-order function value.", "properties": { - "c": { + "v": { "const": "Function", "default": "Function", "enum": [ @@ -1647,7 +1677,7 @@ "additionalProperties": false, "description": "A Sum variant\n\nFor any Sum type where this value meets the type of the variant indicated by the tag", "properties": { - "c": { + "v": { "const": "Sum", "default": "Sum", "enum": [ @@ -1868,7 +1898,7 @@ "additionalProperties": false, "description": "A constant tuple value.", "properties": { - "c": { + "v": { "const": "Tuple", "default": "Tuple", "enum": [ @@ -2153,7 +2183,7 @@ "Sum": "#/$defs/SumValue", "Tuple": "#/$defs/TupleValue" }, - "propertyName": "c" + "propertyName": "v" }, "oneOf": [ { diff --git a/specification/schema/hugr_schema_v1.json b/specification/schema/hugr_schema_v1.json index 9f6979cf4..eadf57675 100644 --- a/specification/schema/hugr_schema_v1.json +++ b/specification/schema/hugr_schema_v1.json @@ -498,6 +498,24 @@ "title": "Const", "type": "object" }, + "CustomConst": { + "additionalProperties": true, + "properties": { + "c": { + "title": "C", + "type": "string" + }, + "v": { + "title": "V" + } + }, + "required": [ + "c", + "v" + ], + "title": "CustomConst", + "type": "object" + }, "CustomOp": { "additionalProperties": true, "description": "A user-defined operation that can be downcasted by the extensions that define\nit.", @@ -725,7 +743,7 @@ "additionalProperties": true, "description": "An extension constant value, that can check it is of a given [CustomType].", "properties": { - "c": { + "v": { "const": "Extension", "default": "Extension", "enum": [ @@ -734,12 +752,24 @@ "title": "ValueTag", "type": "string" }, - "e": { - "title": "CustomConst" + "extensions": { + "items": { + "type": "string" + }, + "title": "Extensions", + "type": "array" + }, + "typ": { + "$ref": "#/$defs/Type" + }, + "value": { + "$ref": "#/$defs/CustomConst" } }, "required": [ - "e" + "extensions", + "typ", + "value" ], "title": "ExtensionValue", "type": "object" @@ -928,7 +958,7 @@ "additionalProperties": true, "description": "A higher-order function value.", "properties": { - "c": { + "v": { "const": "Function", "default": "Function", "enum": [ @@ -1647,7 +1677,7 @@ "additionalProperties": true, "description": "A Sum variant\n\nFor any Sum type where this value meets the type of the variant indicated by the tag", "properties": { - "c": { + "v": { "const": "Sum", "default": "Sum", "enum": [ @@ -1868,7 +1898,7 @@ "additionalProperties": true, "description": "A constant tuple value.", "properties": { - "c": { + "v": { "const": "Tuple", "default": "Tuple", "enum": [ @@ -2153,7 +2183,7 @@ "Sum": "#/$defs/SumValue", "Tuple": "#/$defs/TupleValue" }, - "propertyName": "c" + "propertyName": "v" }, "oneOf": [ { diff --git a/specification/schema/testing_hugr_schema_strict_v1.json b/specification/schema/testing_hugr_schema_strict_v1.json index 2747617b1..ff62e7bd0 100644 --- a/specification/schema/testing_hugr_schema_strict_v1.json +++ b/specification/schema/testing_hugr_schema_strict_v1.json @@ -498,6 +498,24 @@ "title": "Const", "type": "object" }, + "CustomConst": { + "additionalProperties": false, + "properties": { + "c": { + "title": "C", + "type": "string" + }, + "v": { + "title": "V" + } + }, + "required": [ + "c", + "v" + ], + "title": "CustomConst", + "type": "object" + }, "CustomOp": { "additionalProperties": false, "description": "A user-defined operation that can be downcasted by the extensions that define\nit.", @@ -725,7 +743,7 @@ "additionalProperties": false, "description": "An extension constant value, that can check it is of a given [CustomType].", "properties": { - "c": { + "v": { "const": "Extension", "default": "Extension", "enum": [ @@ -734,12 +752,24 @@ "title": "ValueTag", "type": "string" }, - "e": { - "title": "CustomConst" + "extensions": { + "items": { + "type": "string" + }, + "title": "Extensions", + "type": "array" + }, + "typ": { + "$ref": "#/$defs/Type" + }, + "value": { + "$ref": "#/$defs/CustomConst" } }, "required": [ - "e" + "extensions", + "typ", + "value" ], "title": "ExtensionValue", "type": "object" @@ -928,7 +958,7 @@ "additionalProperties": false, "description": "A higher-order function value.", "properties": { - "c": { + "v": { "const": "Function", "default": "Function", "enum": [ @@ -1647,7 +1677,7 @@ "additionalProperties": false, "description": "A Sum variant\n\nFor any Sum type where this value meets the type of the variant indicated by the tag", "properties": { - "c": { + "v": { "const": "Sum", "default": "Sum", "enum": [ @@ -1868,7 +1898,7 @@ "additionalProperties": false, "description": "A constant tuple value.", "properties": { - "c": { + "v": { "const": "Tuple", "default": "Tuple", "enum": [ @@ -2153,7 +2183,7 @@ "Sum": "#/$defs/SumValue", "Tuple": "#/$defs/TupleValue" }, - "propertyName": "c" + "propertyName": "v" }, "oneOf": [ { diff --git a/specification/schema/testing_hugr_schema_v1.json b/specification/schema/testing_hugr_schema_v1.json index 62c062626..d782686ff 100644 --- a/specification/schema/testing_hugr_schema_v1.json +++ b/specification/schema/testing_hugr_schema_v1.json @@ -498,6 +498,24 @@ "title": "Const", "type": "object" }, + "CustomConst": { + "additionalProperties": true, + "properties": { + "c": { + "title": "C", + "type": "string" + }, + "v": { + "title": "V" + } + }, + "required": [ + "c", + "v" + ], + "title": "CustomConst", + "type": "object" + }, "CustomOp": { "additionalProperties": true, "description": "A user-defined operation that can be downcasted by the extensions that define\nit.", @@ -725,7 +743,7 @@ "additionalProperties": true, "description": "An extension constant value, that can check it is of a given [CustomType].", "properties": { - "c": { + "v": { "const": "Extension", "default": "Extension", "enum": [ @@ -734,12 +752,24 @@ "title": "ValueTag", "type": "string" }, - "e": { - "title": "CustomConst" + "extensions": { + "items": { + "type": "string" + }, + "title": "Extensions", + "type": "array" + }, + "typ": { + "$ref": "#/$defs/Type" + }, + "value": { + "$ref": "#/$defs/CustomConst" } }, "required": [ - "e" + "extensions", + "typ", + "value" ], "title": "ExtensionValue", "type": "object" @@ -928,7 +958,7 @@ "additionalProperties": true, "description": "A higher-order function value.", "properties": { - "c": { + "v": { "const": "Function", "default": "Function", "enum": [ @@ -1647,7 +1677,7 @@ "additionalProperties": true, "description": "A Sum variant\n\nFor any Sum type where this value meets the type of the variant indicated by the tag", "properties": { - "c": { + "v": { "const": "Sum", "default": "Sum", "enum": [ @@ -1868,7 +1898,7 @@ "additionalProperties": true, "description": "A constant tuple value.", "properties": { - "c": { + "v": { "const": "Tuple", "default": "Tuple", "enum": [ @@ -2153,7 +2183,7 @@ "Sum": "#/$defs/SumValue", "Tuple": "#/$defs/TupleValue" }, - "propertyName": "c" + "propertyName": "v" }, "oneOf": [ {