codama-nodes 0.10.0

Node specifications and helpers for the Codama standard
Documentation
use crate::{
    AccountNode, ConstantNode, ContextualValueNode, CountNode, DefinedTypeNode, DiscriminatorNode,
    DisplayNode, ErrorNode, EventNode, HasKind, InstructionAccountNode, InstructionArgumentNode,
    InstructionByteDeltaNode, InstructionNode, InstructionRemainingAccountsNode,
    InstructionStatusNode, LinkNode, NodeUnionTrait, PdaNode, PdaSeedNode, PluginNode, ProgramNode,
    ProvidedNode, RegisteredContextualValueNode, RegisteredTypeNode, RegisteredValueNode, RootNode,
    TypeNode, ValueNode,
};
use derive_more::derive::From;
use serde::{Deserialize, Serialize};

#[derive(From, Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Node {
    // Node unions.
    ContextualValue(RegisteredContextualValueNode),
    Count(CountNode),
    Discriminator(DiscriminatorNode),
    Display(DisplayNode),
    Link(LinkNode),
    PdaSeed(PdaSeedNode),
    Type(RegisteredTypeNode),
    Value(RegisteredValueNode),

    // Nodes.
    Account(AccountNode),
    Constant(ConstantNode),
    DefinedType(DefinedTypeNode),
    Error(ErrorNode),
    Event(EventNode),
    Instruction(InstructionNode),
    InstructionAccount(InstructionAccountNode),
    InstructionArgument(InstructionArgumentNode),
    InstructionByteDelta(InstructionByteDeltaNode),
    InstructionRemainingAccounts(InstructionRemainingAccountsNode),
    InstructionStatus(InstructionStatusNode),
    Pda(PdaNode),
    Plugin(PluginNode),
    Program(ProgramNode),
    Provided(ProvidedNode),
    Root(RootNode),
}

impl From<ContextualValueNode> for Node {
    fn from(node: ContextualValueNode) -> Self {
        Node::ContextualValue(node.into())
    }
}

impl From<TypeNode> for Node {
    fn from(node: TypeNode) -> Self {
        match node {
            TypeNode::Link(link) => link.into(),
            _ => Node::Type(node.try_into().unwrap()),
        }
    }
}

impl From<ValueNode> for Node {
    fn from(node: ValueNode) -> Self {
        Node::Value(node.into())
    }
}

impl NodeUnionTrait for Node {}
impl HasKind for Node {
    fn kind(&self) -> &'static str {
        match self {
            Node::ContextualValue(node) => node.kind(),
            Node::Count(node) => node.kind(),
            Node::Discriminator(node) => node.kind(),
            Node::Display(node) => node.kind(),
            Node::Link(node) => node.kind(),
            Node::PdaSeed(node) => node.kind(),
            Node::Type(node) => node.kind(),
            Node::Value(node) => node.kind(),
            Node::Account(node) => node.kind(),
            Node::Constant(node) => node.kind(),
            Node::DefinedType(node) => node.kind(),
            Node::Error(node) => node.kind(),
            Node::Event(node) => node.kind(),
            Node::Instruction(node) => node.kind(),
            Node::InstructionAccount(node) => node.kind(),
            Node::InstructionArgument(node) => node.kind(),
            Node::InstructionByteDelta(node) => node.kind(),
            Node::InstructionRemainingAccounts(node) => node.kind(),
            Node::InstructionStatus(node) => node.kind(),
            Node::Pda(node) => node.kind(),
            Node::Plugin(node) => node.kind(),
            Node::Program(node) => node.kind(),
            Node::Provided(node) => node.kind(),
            Node::Root(node) => node.kind(),
        }
    }
}

impl HasKind for Option<Node> {
    fn kind(&self) -> &'static str {
        match self {
            Some(node) => node.kind(),
            None => "None",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{NumberTypeNode, NumberValueNode, U32};

    #[test]
    fn kind() {
        let node: Node = ProgramNode::default().into();
        assert_eq!(node.kind(), "programNode");
    }

    #[test]
    fn type_node_to_json() {
        let node: Node = NumberTypeNode::le(U32).into();
        let json = serde_json::to_string(&node).unwrap();
        assert_eq!(
            json,
            r#"{"kind":"numberTypeNode","format":"u32","endian":"le"}"#
        );
    }

    #[test]
    fn type_node_from_json() {
        let json = r#"{"kind":"numberTypeNode","format":"u32","endian":"le"}"#;
        let node: Node = serde_json::from_str(json).unwrap();
        assert_eq!(
            node,
            Node::Type(RegisteredTypeNode::Number(NumberTypeNode::le(U32)))
        );
    }

    #[test]
    fn defined_type_to_json() {
        let node: Node = DefinedTypeNode::new("myType", NumberTypeNode::le(U32)).into();
        let json = serde_json::to_string(&node).unwrap();
        assert_eq!(
            json,
            r#"{"kind":"definedTypeNode","name":"myType","type":{"kind":"numberTypeNode","format":"u32","endian":"le"}}"#
        );
    }

    #[test]
    fn defined_type_from_json() {
        let json = r#"{"kind":"definedTypeNode","name":"myType","type":{"kind":"numberTypeNode","format":"u32","endian":"le"}}"#;
        let node: Node = serde_json::from_str(json).unwrap();
        assert_eq!(
            node,
            Node::DefinedType(DefinedTypeNode::new("myType", NumberTypeNode::le(U32)))
        );
    }

    #[test]
    fn constant_to_json() {
        let node: Node = ConstantNode::new(
            "myConstant",
            NumberTypeNode::le(U32),
            NumberValueNode::new(42u32),
        )
        .into();
        let json = serde_json::to_string(&node).unwrap();
        assert_eq!(
            json,
            r#"{"kind":"constantNode","name":"myConstant","type":{"kind":"numberTypeNode","format":"u32","endian":"le"},"value":{"kind":"numberValueNode","number":42}}"#
        );
    }

    #[test]
    fn constant_from_json() {
        let json = r#"{"kind":"constantNode","name":"myConstant","type":{"kind":"numberTypeNode","format":"u32","endian":"le"},"value":{"kind":"numberValueNode","number":42}}"#;
        let node: Node = serde_json::from_str(json).unwrap();
        assert_eq!(
            node,
            Node::Constant(ConstantNode::new(
                "myConstant",
                NumberTypeNode::le(U32),
                NumberValueNode::new(42u32)
            ))
        );
    }
}