Move all persistent node metadata into the network

This commit is contained in:
Adam
2024-09-06 23:18:04 -07:00
parent de31dbfb19
commit 0f18438243
11 changed files with 539 additions and 388 deletions
@@ -242,7 +242,12 @@ impl<'a> ModifyInputsContext<'a> {
// Take until another layer node is found (but not the first layer node) // Take until another layer node is found (but not the first layer node)
let existing_node_id = upstream let existing_node_id = upstream
.take_while(|node_id| is_traversal_start(*node_id) || !self.network_interface.is_layer(node_id, &[])) .take_while(|node_id| is_traversal_start(*node_id) || !self.network_interface.is_layer(node_id, &[]))
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|node_reference| node_reference == reference)); .find(|node_id| {
let Some(node_reference) = self.network_interface.reference(node_id, &[]) else {
log::error!("Node reference does not exist in ModifyInputsContext::existing_node_id");
return false;
};
node_reference.as_ref().is_some_and(|node_reference| node_reference == reference)});
// Create a new node if the node does not exist and update its inputs // Create a new node if the node does not exist and update its inputs
existing_node_id.or_else(|| { existing_node_id.or_else(|| {
@@ -2,7 +2,7 @@ use super::node_properties;
use super::utility_types::FrontendNodeType; use super::utility_types::FrontendNodeType;
use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::network_interface::{ use crate::messages::portfolio::document::utility_types::network_interface::{
DocumentNodeMetadata, DocumentNodePersistentMetadata, NodeNetworkInterface, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodeTemplate, NodeTypePersistentMetadata, DocumentNodeMetadata, DocumentNodePersistentMetadata, NodeNetworkInterface, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodeTemplate,
}; };
use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::Message; use crate::messages::prelude::Message;
@@ -1087,9 +1087,11 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
input, input,
}); });
responses.add(PropertiesPanelMessage::Refresh); responses.add(PropertiesPanelMessage::Refresh);
if (!network_interface.reference(&node_id, selection_network_path).is_some_and(|reference| reference == "Imaginate") || input_index == 0) let Some(reference) = network_interface.reference(&node_id, selection_network_path) else {
&& network_interface.connected_to_output(&node_id, selection_network_path) log::error!("Could not get reference for node: {node_id:?} in NodeGraphMessage::SetInputValue");
{ return;
};
if (!reference.as_ref().is_some_and(|reference| reference == "Imaginate") || input_index == 0) && network_interface.connected_to_output(&node_id, selection_network_path) {
responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::RunDocumentGraph);
} }
} }
@@ -1182,12 +1184,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids }) responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids })
} }
NodeGraphMessage::ToggleLocked { node_id } => { NodeGraphMessage::ToggleLocked { node_id } => {
let Some(node_metadata) = network_interface.network_metadata(&[]).unwrap().persistent_metadata.node_metadata.get(&node_id) else { let locked = !network_interface.is_locked(&node_id, &[]);
log::error!("Cannot get node {:?} in NodeGraphMessage::ToggleLocked", node_id);
return;
};
let locked = !node_metadata.persistent_metadata.locked;
responses.add(DocumentMessage::AddTransaction); responses.add(DocumentMessage::AddTransaction);
responses.add(NodeGraphMessage::SetLocked { node_id, locked }); responses.add(NodeGraphMessage::SetLocked { node_id, locked });
@@ -1637,17 +1634,19 @@ impl NodeGraphMessageHandler {
log::error!("Could not get nested network when collecting nodes"); log::error!("Could not get nested network when collecting nodes");
return Vec::new(); return Vec::new();
}; };
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
log::error!("Could not get network_metadata when collecting nodes");
return Vec::new();
};
let mut nodes = Vec::new(); let mut nodes = Vec::new();
for (&node_id, node) in &network.nodes { for (&node_id, node) in &network.nodes {
let node_id_path = &[breadcrumb_network_path, (&[node_id])].concat(); let node_id_path = &[breadcrumb_network_path, (&[node_id])].concat();
let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(&node_id) else {
log::error!("Could not get node_metadata for {node_id_path:?}"); let Some(input_names) = network_interface.input_names(&node_id, breadcrumb_network_path) else {
continue; log::error!("Could not get input names for node: {node_id}");
return Vec::new();
};
let Some(output_names) = network_interface.output_names(&node_id, breadcrumb_network_path) else {
log::error!("Could not get output names for node: {node_id}");
return Vec::new();
}; };
let frontend_graph_inputs = node.inputs.iter().enumerate().map(|(index, _)| { let frontend_graph_inputs = node.inputs.iter().enumerate().map(|(index, _)| {
@@ -1657,9 +1656,7 @@ impl NodeGraphMessageHandler {
// TODO: Should display the color of the "most commonly relevant" (we'd need some sort of precedence) data type it allows given the current generic form that's constrained by the other present connections. // TODO: Should display the color of the "most commonly relevant" (we'd need some sort of precedence) data type it allows given the current generic form that's constrained by the other present connections.
let data_type = FrontendGraphDataType::with_type(&node_type); let data_type = FrontendGraphDataType::with_type(&node_type);
let input_name = node_metadata let input_name = input_names
.persistent_metadata
.input_names
.get(index) .get(index)
.cloned() .cloned()
.unwrap_or(network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path).nested_type().to_string()); .unwrap_or(network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path).nested_type().to_string());
@@ -1727,16 +1724,8 @@ impl NodeGraphMessageHandler {
} else { } else {
FrontendGraphDataType::General FrontendGraphDataType::General
}; };
let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(&node_id) else {
log::error!("Could not get node_metadata when getting output for {node_id}"); let output_name = output_names.get(index).map(|output_name| output_name.to_string()).unwrap_or(format!("Output {}", index + 1));
continue;
};
let output_name = node_metadata
.persistent_metadata
.output_names
.get(index)
.map(|output_name| output_name.to_string())
.unwrap_or(format!("Output {}", index + 1));
let connected_to = outward_wires.get(&OutputConnector::node(node_id, index)).cloned().unwrap_or_default(); let connected_to = outward_wires.get(&OutputConnector::node(node_id, index)).cloned().unwrap_or_default();
exposed_outputs.push(FrontendGraphOutput { exposed_outputs.push(FrontendGraphOutput {
@@ -1776,9 +1765,7 @@ impl NodeGraphMessageHandler {
nodes.push(FrontendNode { nodes.push(FrontendNode {
id: node_id, id: node_id,
is_layer: network_interface is_layer: network_interface.is_layer(&node_id, breadcrumb_network_path),
.node_metadata(&node_id, breadcrumb_network_path)
.is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
can_be_layer: can_be_layer_lookup.contains(&node_id), can_be_layer: can_be_layer_lookup.contains(&node_id),
reference: None, reference: None,
display_name: network_interface.frontend_display_name(&node_id, breadcrumb_network_path), display_name: network_interface.frontend_display_name(&node_id, breadcrumb_network_path),
@@ -1836,8 +1823,8 @@ impl NodeGraphMessageHandler {
} }
} }
for (&node_id, node_metadata) in &network_interface.network_metadata(&[]).unwrap().persistent_metadata.node_metadata { for &node_id in network_interface.network(&[]).unwrap().nodes.keys() {
if node_metadata.persistent_metadata.is_layer() { if network_interface.is_layer(&node_id, &[]) {
let layer = LayerNodeIdentifier::new(node_id, network_interface, &[]); let layer = LayerNodeIdentifier::new(node_id, network_interface, &[]);
let children_allowed = let children_allowed =
@@ -2343,7 +2343,15 @@ pub fn index_properties(document_node: &DocumentNode, node_id: NodeId, _context:
} }
pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> LayoutGroup { pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> LayoutGroup {
let reference = context.network_interface.reference(&node_id, context.selection_network_path).clone(); let Some(reference) = context.network_interface.reference(&node_id, context.selection_network_path).cloned() else {
log::error!("Node {node_id} has no reference in generate_node_properties");
return LayoutGroup::Section {
name: "Unknown".to_string(),
visible: true,
id: node_id.0,
layout: unknown_node_properties(&"Unknown".to_string()),
};
};
let layout = if let Some(ref reference) = reference { let layout = if let Some(ref reference) = reference {
match super::document_node_definitions::resolve_document_node_type(reference) { match super::document_node_definitions::resolve_document_node_type(reference) {
Some(document_node_type) => (document_node_type.properties)(document_node, node_id, context), Some(document_node_type) => (document_node_type.properties)(document_node, node_id, context),
File diff suppressed because it is too large Load Diff
@@ -415,15 +415,11 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
.cloned() .cloned()
.collect::<Vec<NodeId>>() .collect::<Vec<NodeId>>()
{ {
if let Some(reference) = document let Some(reference) = document.network_interface.reference(&node_id, &[]) else {
.network_interface log::error!("could not get reference in deserialize_document");
.network_metadata(&[]) continue;
.unwrap() };
.persistent_metadata if let Some(reference) = reference {
.node_metadata
.get(node_id)
.and_then(|node| node.persistent_metadata.reference.as_ref())
{
let node_definition = crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type(reference).unwrap(); let node_definition = crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type(reference).unwrap();
let default_definition_node = node_definition.default_node_template(); let default_definition_node = node_definition.default_node_template();
document.network_interface.set_implementation(node_id, &[], default_definition_node.document_node.implementation); document.network_interface.set_implementation(node_id, &[], default_definition_node.document_node.implementation);
@@ -433,14 +429,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
if document if document
.network_interface .network_interface
.network_metadata(&[]) .network(&[])
.unwrap() .unwrap()
.persistent_metadata .nodes
.node_metadata .keys()
.iter() .any(|node_id|*node_id == NodeId(0) && document.network_interface.reference(node_id, &[]).cloned().flatten().is_some_and(|reference| reference == "Output"))
.any(|(node_id, node)| node.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Output") && *node_id == NodeId(0))
{ {
document.network_interface.delete_nodes(vec![NodeId(0)], true, &[]); document.network_interface.delete_nodes(vec![NodeId(0)], false, &[]);
} }
let node_ids = document.network_interface.network(&[]).unwrap().nodes.keys().cloned().collect::<Vec<_>>(); let node_ids = document.network_interface.network(&[]).unwrap().nodes.keys().cloned().collect::<Vec<_>>();
@@ -449,14 +444,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
log::error!("could not get node in deserialize_document"); log::error!("could not get node in deserialize_document");
continue; continue;
}; };
let Some(node_metadata) = document.network_interface.network_metadata(&[]).unwrap().persistent_metadata.node_metadata.get(node_id) else {
log::error!("could not get node metadata for node {node_id} in deserialize_document");
continue;
};
// Upgrade Fill nodes to the format change in #1778 // Upgrade Fill nodes to the format change in #1778
// TODO: Eventually remove this (probably starting late 2024) // TODO: Eventually remove this (probably starting late 2024)
let Some(ref reference) = node_metadata.persistent_metadata.reference.clone() else { let Some(ref reference) = document.network_interface.reference(node_id, &[]).cloned().flatten() else {
continue; continue;
}; };
if reference == "Fill" && node.inputs.len() == 8 { if reference == "Fill" && node.inputs.len() == 8 {
@@ -174,8 +174,14 @@ impl<'a> NodeGraphLayer<'a> {
/// Node id of a node if it exists in the layer's primary flow /// Node id of a node if it exists in the layer's primary flow
pub fn upstream_node_id_from_name(&self, node_name: &str) -> Option<NodeId> { pub fn upstream_node_id_from_name(&self, node_name: &str) -> Option<NodeId> {
self.horizontal_layer_flow() self.horizontal_layer_flow()
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == node_name)) .find(|node_id| {
let Some(reference) = self.network_interface.reference(node_id, &[]) else {
log::error!("Reference could not be found for node {node_id} in upstream_node_id_from_name");
return false };
reference.as_ref().is_some_and(|reference| reference == node_name)
})
} }
/// Find all of the inputs of a specific node within the layer's primary flow, up until the next layer is reached. /// Find all of the inputs of a specific node within the layer's primary flow, up until the next layer is reached.
@@ -183,7 +189,13 @@ impl<'a> NodeGraphLayer<'a> {
self.horizontal_layer_flow() self.horizontal_layer_flow()
.skip(1)// Skip self .skip(1)// Skip self
.take_while(|node_id| !self.network_interface.is_layer(node_id,&[])) .take_while(|node_id| !self.network_interface.is_layer(node_id,&[]))
.find(|node_id| self.network_interface.reference(node_id,&[]).is_some_and(|reference| reference == node_name)) .find(|node_id|
{
let Some(reference) = self.network_interface.reference(node_id, &[]) else {
log::error!("Reference could not be found for node {node_id} in upstream_node_id_from_name");
return false };
reference.as_ref().is_some_and(|reference| reference == node_name)
})
.and_then(|node_id| self.network_interface.network(&[]).unwrap().nodes.get(&node_id).map(|node| &node.inputs)) .and_then(|node_id| self.network_interface.network(&[]).unwrap().nodes.get(&node_id).map(|node| &node.inputs))
} }
@@ -3,8 +3,8 @@ use crate::messages::portfolio::document::graph_operation::transform_utils::{get
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::network_interface::FlowType; use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use graph_craft::document::value::TaggedValue; use graph_craft::document::value::TaggedValue;
use graph_craft::document::NodeId; use graph_craft::document::NodeId;
@@ -272,6 +272,10 @@ impl BrushToolData {
continue; continue;
}; };
let Some(reference) = document.network_interface.reference(&node_id, &[]) else { let Some(reference) = document.network_interface.reference(&node_id, &[]) else {
log::error!("Could not get reference for node {node_id} in load_existing_strokes");
continue;
};
let Some(reference) = reference else {
continue; continue;
}; };
if reference == "Brush" && node_id != layer.to_node() { if reference == "Brush" && node_id != layer.to_node() {
+16 -13
View File
@@ -702,13 +702,12 @@ impl EditorHandle {
let document = editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap(); let document = editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap();
for node in document for node in document
.network_interface .network_interface
.network_metadata(&[]) .network(&[])
.unwrap() .unwrap()
.persistent_metadata .nodes
.node_metadata .keys()
.iter() .filter(|node_id| document.network_interface.reference(node_id, &[]).cloned().flatten().is_some_and(|reference| reference == "Artboard"))
.filter(|(_, d)| d.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Artboard")) .cloned()
.map(|(id, _)| *id)
.collect::<Vec<_>>() .collect::<Vec<_>>()
{ {
let Some(document_node) = document.network_interface.network(&[]).unwrap().nodes.get(&node) else { let Some(document_node) = document.network_interface.network(&[]).unwrap().nodes.get(&node) else {
@@ -718,7 +717,12 @@ impl EditorHandle {
if let Some(network) = document_node.implementation.get_network() { if let Some(network) = document_node.implementation.get_network() {
let mut nodes_to_upgrade = Vec::new(); let mut nodes_to_upgrade = Vec::new();
for (node_id, _) in network.nodes.iter().collect::<Vec<_>>() { for (node_id, _) in network.nodes.iter().collect::<Vec<_>>() {
if document.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == "To Artboard") if document
.network_interface
.reference(node_id, &[])
.cloned()
.flatten()
.is_some_and(|reference| reference == "To Artboard")
&& document && document
.network_interface .network_interface
.network(&[]) .network(&[])
@@ -773,13 +777,12 @@ impl EditorHandle {
document.network_interface.load_structure(); document.network_interface.load_structure();
for node in document for node in document
.network_interface .network_interface
.network_metadata(&[]) .network(&[])
.unwrap() .unwrap()
.persistent_metadata .nodes
.node_metadata .keys()
.iter() .filter(|node_id| document.network_interface.reference(node_id, &[]).cloned().flatten().is_some_and(|reference| reference == "Merge"))
.filter(|(_, d)| d.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Merge")) .cloned()
.map(|(id, _)| *id)
.collect::<Vec<_>>() .collect::<Vec<_>>()
{ {
let layer = LayerNodeIdentifier::new(node, &document.network_interface, &[]); let layer = LayerNodeIdentifier::new(node, &document.network_interface, &[]);
+101 -1
View File
@@ -12,7 +12,7 @@ use glam::{DVec2, IVec2};
use log::Metadata; use log::Metadata;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
pub mod value; pub mod value;
@@ -1630,6 +1630,106 @@ pub struct NetworkEdgeDistance {
/// The viewport pixel distance between the left edge of the node graph and the imports. /// The viewport pixel distance between the left edge of the node graph and the imports.
pub imports_to_edge_distance: DVec2, pub imports_to_edge_distance: DVec2,
} }
/// A layer can either be position as Absolute or in a Stack
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub enum LayerPosition {
// Position of the layer in grid spaces. Measured from the top left corner of the layer, not including the left chain. This means it is always half a grid space to the left of the thumbnail.
Absolute(IVec2),
// A layer is in a Stack when it feeds into the bottom input of a layer. The Y position stores the vertical distance between the layer and its upstream sibling/parent.
Stack(u32),
}
/// A node can either be position as Absolute or in a Chain
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub enum NodePosition {
// Position of the node in grid spaces
Absolute(IVec2),
// In a chain the position is based on the number of nodes to the first layer node
Chain,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub enum NodeTypePersistentMetadata {
Layer(LayerMetadata),
Node(NodePersistentMetadata),
}
impl Default for NodeTypePersistentMetadata {
fn default() -> Self {
NodeTypePersistentMetadata::node(IVec2::ZERO)
}
}
impl NodeTypePersistentMetadata {
pub fn node(position: IVec2) -> NodeTypePersistentMetadata {
NodeTypePersistentMetadata::Node(NodePersistentMetadata {
position: NodePosition::Absolute(position),
})
}
pub fn layer(position: IVec2) -> NodeTypePersistentMetadata {
NodeTypePersistentMetadata::Layer(LayerMetadata {
persistent_metadata: LayerPersistentMetadata {
position: LayerPosition::Absolute(position),
},
transient_metadata: Default::default(),
})
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize, DynAny)]
pub struct LayerMetadata {
pub persistent_metadata: LayerPersistentMetadata,
#[serde(skip)]
pub transient_metadata: LayerTransientMetadata,
}
impl Hash for LayerMetadata {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.persistent_metadata.hash(state);
}
}
impl Clone for LayerMetadata {
fn clone(&self) -> Self {
LayerMetadata {
persistent_metadata: self.persistent_metadata.clone(),
transient_metadata: Default::default(),
}
}
}
impl PartialEq for LayerMetadata {
fn eq(&self, other: &Self) -> bool {
self.persistent_metadata == other.persistent_metadata
}
}
/// All fields in LayerMetadata should automatically be updated by using the network interface API
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub struct LayerPersistentMetadata {
/// Stores the position of a layer node, which can either be Absolute or Stack
pub position: LayerPosition,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, DynAny)]
pub struct LayerTransientMetadata {
/// All nodes that should be moved when the layer is moved.
pub owned_nodes: TransientMetadata<HashSet<NodeId>>,
// Stores the width in grid cell units for layer nodes from the left edge of the thumbnail (+12px padding since thumbnail ends between grid spaces) to the left end of the node
/// This is necessary since calculating the layer width through web_sys is very slow
pub layer_width: TransientMetadata<u32>,
// Should not be a performance concern to calculate when needed with chain_width.
// Stores the width in grid cell units for layer nodes from the left edge of the thumbnail to the end of the chain
// chain_width: u32,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub struct NodePersistentMetadata {
/// Stores the position of a non layer node, which can either be Absolute or Chain
pub position: NodePosition,
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@@ -189,6 +189,10 @@ tagged_value! {
OutwardWires(TransientMetadata<HashMap<crate::document::OutputConnector, Vec<crate::document::InputConnector>>>), OutwardWires(TransientMetadata<HashMap<crate::document::OutputConnector, Vec<crate::document::InputConnector>>>),
ImportExportPorts(TransientMetadata<crate::document::Ports>), ImportExportPorts(TransientMetadata<crate::document::Ports>),
RoundedNetworkEdgeDistance(TransientMetadata<crate::document::NetworkEdgeDistance>), RoundedNetworkEdgeDistance(TransientMetadata<crate::document::NetworkEdgeDistance>),
// Persistent Node Metadata
OptionalString(Option<String>),
VecString(Vec<String>),
NodeTypeMetadata(crate::document::NodeTypePersistentMetadata),
} }
impl TaggedValue { impl TaggedValue {