1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use super::Args;
use crate::error::InputParseError;

/// Parsed [Args] consisting of [Inputs] for execution flows, as well as an
/// optional function name/definition.
///
/// TODO: Extend via enumeration for singular objects/values.
///
/// [Inputs]: super::Input
#[derive(Clone, Debug, PartialEq)]
pub struct Parsed<T> {
    args: Args<T>,
    fun: Option<String>,
}

impl<T> Parsed<T> {
    /// Initiate [Parsed] data structure with only [Args].
    pub fn with(args: Args<T>) -> Self {
        Parsed { args, fun: None }
    }

    /// Initiate [Parsed] data structure with a function name and
    /// [Args].
    pub fn with_fn(fun: String, args: Args<T>) -> Self {
        Parsed {
            args,
            fun: Some(fun),
        }
    }

    /// Parsed arguments.
    pub fn args(&self) -> &Args<T> {
        &self.args
    }

    /// Turn [Parsed] structure into owned [Args].
    pub fn into_args(self) -> Args<T> {
        self.args
    }

    /// Parsed function named.
    pub fn fun(&self) -> Option<String> {
        self.fun.as_ref().map(|f| f.to_string())
    }
}

impl<T> From<Parsed<T>> for Args<T> {
    fn from(apply: Parsed<T>) -> Self {
        apply.args
    }
}

/// Interface for [Instruction] implementations, relying on `homestore-core`
/// to implement custom parsing specifics.
///
/// # Example
///
/// ```
/// use homestar_invocation::{
///     task::{
///         instruction::{Ability, Args, Input, Parse},
///         Instruction,
///     },
///     Unit,
///  };
/// use libipld::Ipld;
/// use url::Url;
///
/// let wasm = "bafkreihxcyjgyrz437ewzi7md55uqt2zf6yr3zn7xrfi4orc34xdc5jgrm".to_string();
/// let resource = Url::parse(format!("ipfs://{wasm}").as_str()).unwrap();
///
/// let inst = Instruction::unique(
///     resource,
///     Ability::from("wasm/run"),
///     Input::<Unit>::Ipld(Ipld::List(vec![Ipld::Bool(true)]))
/// );
///
/// let parsed = inst.input().parse().unwrap();
///
/// // turn into Args for invocation:
/// let args: Args<Unit> = parsed.try_into().unwrap();
/// ```
///
/// [Instruction]: crate::task::Instruction
pub trait Parse<T> {
    /// Function returning [Parsed] structure for execution/invocation.
    ///
    /// Note: meant to come before the `resolve` step
    /// during runtime execution.
    fn parse(&self) -> Result<Parsed<T>, InputParseError<T>>;
}