txtx-core 0.4.16

Primitives for parsing, analyzing and executing Txtx runbooks
Documentation
use super::{arg_checker, to_diag};
use txtx_addon_kit::{
    define_function, indoc,
    types::{
        diagnostics::Diagnostic,
        functions::{FunctionImplementation, FunctionSpecification},
        types::{Type, Value},
    },
};
use txtx_addon_kit::{hex, types::AuthorizationContext};

lazy_static! {
    pub static ref FUNCTIONS: Vec<FunctionSpecification> = vec![
        define_function! {
            BigEndianEncodeU32 => {
                name: "encode_big_endian_u32",
                documentation: "`encode_big_endian_u32` encodes a u32 to a big-endian hex string",
                example: indoc!{r#"
                    output "encoded" {
                        value = encode_big_endian_u32(1)
                    }
                    > encoded: 0x00000001
                "#},
                inputs: [
                    integer_u32: {
                        documentation: "The integer to encode",
                        typing: vec![Type::integer()]
                    }
                ],
                output: {
                    documentation: "The integer encoded as a hex string",
                    typing: Type::string()
                },
            }
        },
        define_function! {
            BigEndianEncodeU64 => {
                name: "encode_big_endian_u64",
                documentation: "`encode_big_endian_u64` encodes a u64 to a big-endian hex string",
                example: indoc!{r#"
                    output "encoded" {
                        value = encode_big_endian_u64(1)
                    }
                    > encoded: 0x0000000000000001
                "#},
                inputs: [
                    integer_u32: {
                        documentation: "The integer to encode",
                        typing: vec![Type::integer()]
                    }
                ],
                output: {
                    documentation: "The integer encoded as a hex string",
                    typing: Type::string()
                },
            }
        }
    ];
}

pub struct BigEndianEncodeU32;
impl FunctionImplementation for BigEndianEncodeU32 {
    fn check_instantiability(
        _fn_spec: &FunctionSpecification,
        _auth_ctx: &AuthorizationContext,
        _args: &Vec<Type>,
    ) -> Result<Type, Diagnostic> {
        unimplemented!()
    }

    fn run(
        fn_spec: &FunctionSpecification,
        _auth_ctx: &AuthorizationContext,
        args: &Vec<Value>,
    ) -> Result<Value, Diagnostic> {
        arg_checker(fn_spec, args)?;

        let value = parse_integer::<u32>(fn_spec, args)?;
        let bytes = value.to_be_bytes();

        Ok(Value::string(format!("0x{}", hex::encode(bytes))))
    }
}

pub struct BigEndianEncodeU64;
impl FunctionImplementation for BigEndianEncodeU64 {
    fn check_instantiability(
        _fn_spec: &FunctionSpecification,
        _auth_ctx: &AuthorizationContext,
        _args: &Vec<Type>,
    ) -> Result<Type, Diagnostic> {
        unimplemented!()
    }

    fn run(
        fn_spec: &FunctionSpecification,
        _auth_ctx: &AuthorizationContext,
        args: &Vec<Value>,
    ) -> Result<Value, Diagnostic> {
        arg_checker(fn_spec, args)?;

        let value = parse_integer::<u64>(fn_spec, args)?;
        let bytes = value.to_be_bytes();

        Ok(Value::string(format!("0x{}", hex::encode(bytes))))
    }
}

fn parse_integer<T>(fn_spec: &FunctionSpecification, args: &Vec<Value>) -> Result<T, Diagnostic>
where
    T: TryFrom<i128>,
{
    let Value::Integer(i) = args.get(0).unwrap() else {
        return Err(to_diag(fn_spec, "expected argument 0 to be an integer".to_string()));
    };

    let value: T =
        (*i).try_into().map_err(|_| to_diag(fn_spec, format!("integer {} is out of range", i)))?;

    Ok(value)
}