bladeink 1.2.5

This is a Rust port of inkle's ink, a scripting language for writing interactive narrative.
Documentation
use std::fmt;

use strum::Display;

use crate::object::{Object, RTObject};

#[derive(PartialEq, Display, Clone, Copy)]
pub enum CommandType {
    EvalStart,
    EvalOutput,
    EvalEnd,
    Duplicate,
    PopEvaluatedValue,
    PopFunction,
    PopTunnel,
    BeginString,
    EndString,
    NoOp,
    ChoiceCount,
    Turns,
    TurnsSince,
    ReadCount,
    Random,
    SeedRandom,
    VisitIndex,
    SequenceShuffleIndex,
    StartThread,
    Done,
    End,
    ListFromInt,
    ListRange,
    ListRandom,
    BeginTag,
    EndTag,
}

const EVAL_START_NAME: &str = "ev";
const EVAL_OUTPUT_NAME: &str = "out";
const EVAL_END_NAME: &str = "/ev";
const DUPLICATE_NAME: &str = "du";
const POP_EVALUATED_VALUE_NAME: &str = "pop";
const POP_FUNCTION_NAME: &str = "~ret";
const POP_TUNNEL_NAME: &str = "->->";
const BEGIN_STRING_NAME: &str = "str";
const END_STRING_NAME: &str = "/str";
const NO_OP_NAME: &str = "nop";
const CHOICE_COUNT_NAME: &str = "choiceCnt";
const TURNS_NAME: &str = "turn";
const TURNS_SINCE_NAME: &str = "turns";
const READ_COUNT_NAME: &str = "readc";
const RANDOM_NAME: &str = "rnd";
const SEED_RANDOM_NAME: &str = "srnd";
const VISIT_INDEX_NAME: &str = "visit";
const SEQUENCE_SHUFFLE_INDEX_NAME: &str = "seq";
const START_THREAD_NAME: &str = "thread";
const DONE_NAME: &str = "done";
const END_NAME: &str = "end";
const LIST_FROM_INT_NAME: &str = "listInt";
const LIST_RANGE_NAME: &str = "range";
const LIST_RANDOM_NAME: &str = "lrnd";
const BEGIN_TAG_NAME: &str = "#";
const END_TAG_NAME: &str = "/#";

pub struct ControlCommand {
    obj: Object,
    pub command_type: CommandType,
}

impl ControlCommand {
    pub fn new_from_name(name: &str) -> Option<Self> {
        match name {
            EVAL_START_NAME => Some(Self::new(CommandType::EvalStart)),
            EVAL_OUTPUT_NAME => Some(Self::new(CommandType::EvalOutput)),
            EVAL_END_NAME => Some(Self::new(CommandType::EvalEnd)),
            DUPLICATE_NAME => Some(Self::new(CommandType::Duplicate)),
            POP_EVALUATED_VALUE_NAME => Some(Self::new(CommandType::PopEvaluatedValue)),
            POP_FUNCTION_NAME => Some(Self::new(CommandType::PopFunction)),
            POP_TUNNEL_NAME => Some(Self::new(CommandType::PopTunnel)),
            BEGIN_STRING_NAME => Some(Self::new(CommandType::BeginString)),
            END_STRING_NAME => Some(Self::new(CommandType::EndString)),
            NO_OP_NAME => Some(Self::new(CommandType::NoOp)),
            CHOICE_COUNT_NAME => Some(Self::new(CommandType::ChoiceCount)),
            TURNS_NAME => Some(Self::new(CommandType::Turns)),
            TURNS_SINCE_NAME => Some(Self::new(CommandType::TurnsSince)),
            READ_COUNT_NAME => Some(Self::new(CommandType::ReadCount)),
            RANDOM_NAME => Some(Self::new(CommandType::Random)),
            SEED_RANDOM_NAME => Some(Self::new(CommandType::SeedRandom)),
            VISIT_INDEX_NAME => Some(Self::new(CommandType::VisitIndex)),
            SEQUENCE_SHUFFLE_INDEX_NAME => Some(Self::new(CommandType::SequenceShuffleIndex)),
            START_THREAD_NAME => Some(Self::new(CommandType::StartThread)),
            DONE_NAME => Some(Self::new(CommandType::Done)),
            END_NAME => Some(Self::new(CommandType::End)),
            LIST_FROM_INT_NAME => Some(Self::new(CommandType::ListFromInt)),
            LIST_RANGE_NAME => Some(Self::new(CommandType::ListRange)),
            LIST_RANDOM_NAME => Some(Self::new(CommandType::ListRandom)),
            BEGIN_TAG_NAME => Some(Self::new(CommandType::BeginTag)),
            END_TAG_NAME => Some(Self::new(CommandType::EndTag)),
            _ => None,
        }
    }

    pub fn get_name(c: CommandType) -> String {
        match c {
            CommandType::EvalStart => EVAL_START_NAME.to_owned(),
            CommandType::EvalOutput => EVAL_OUTPUT_NAME.to_owned(),
            CommandType::EvalEnd => EVAL_END_NAME.to_owned(),
            CommandType::Duplicate => DUPLICATE_NAME.to_owned(),
            CommandType::PopEvaluatedValue => POP_EVALUATED_VALUE_NAME.to_owned(),
            CommandType::PopFunction => POP_FUNCTION_NAME.to_owned(),
            CommandType::PopTunnel => POP_TUNNEL_NAME.to_owned(),
            CommandType::BeginString => BEGIN_STRING_NAME.to_owned(),
            CommandType::EndString => END_STRING_NAME.to_owned(),
            CommandType::NoOp => NO_OP_NAME.to_owned(),
            CommandType::ChoiceCount => CHOICE_COUNT_NAME.to_owned(),
            CommandType::Turns => TURNS_NAME.to_owned(),
            CommandType::TurnsSince => TURNS_SINCE_NAME.to_owned(),
            CommandType::ReadCount => READ_COUNT_NAME.to_owned(),
            CommandType::Random => RANDOM_NAME.to_owned(),
            CommandType::SeedRandom => SEED_RANDOM_NAME.to_owned(),
            CommandType::VisitIndex => VISIT_INDEX_NAME.to_owned(),
            CommandType::SequenceShuffleIndex => SEQUENCE_SHUFFLE_INDEX_NAME.to_owned(),
            CommandType::StartThread => START_THREAD_NAME.to_owned(),
            CommandType::Done => DONE_NAME.to_owned(),
            CommandType::End => END_NAME.to_owned(),
            CommandType::ListFromInt => LIST_FROM_INT_NAME.to_owned(),
            CommandType::ListRange => LIST_RANGE_NAME.to_owned(),
            CommandType::ListRandom => LIST_RANDOM_NAME.to_owned(),
            CommandType::BeginTag => BEGIN_TAG_NAME.to_owned(),
            CommandType::EndTag => END_TAG_NAME.to_owned(),
        }
    }

    pub fn new(command_type: CommandType) -> Self {
        Self {
            obj: Object::new(),
            command_type,
        }
    }
}

impl RTObject for ControlCommand {
    fn get_object(&self) -> &Object {
        &self.obj
    }
}

impl fmt::Display for ControlCommand {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.command_type)
    }
}