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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::prelude::*;
use casper_types::bytesrepr::FromBytes;
use casper_types::{CLTyped, RuntimeArgs, U512};
use serde::{Deserialize, Serialize};

/// Represents a call definition, which includes the method name, runtime arguments, attached value, and mutability flag.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CallDef {
    entry_point: String,
    args: RuntimeArgs,
    amount: U512,
    is_mut: bool
}

impl CallDef {
    /// Creates a new `CallDef` instance with the given method name and runtime arguments.
    ///
    /// # Arguments
    ///
    /// * `method` - The method name.
    /// * `is_mut` - Indicates if the call is mutable.
    /// * `args` - The runtime arguments.
    ///
    /// # Example
    ///
    /// ```
    /// # use odra_core::CallDef;
    /// # use casper_types::RuntimeArgs;
    /// let method = "my_method";
    /// let args = RuntimeArgs::new();
    /// let call_def = CallDef::new(method, false, args);
    /// ```
    pub fn new<T: ToString>(method: T, is_mut: bool, args: RuntimeArgs) -> Self {
        CallDef {
            entry_point: method.to_string(),
            args,
            amount: U512::zero(),
            is_mut
        }
    }

    /// Sets the attached value for the `CallDef` instance.
    ///
    /// # Arguments
    ///
    /// * `amount` - The attached value.
    ///
    /// # Returns
    ///
    /// The modified `CallDef` instance.
    ///
    /// # Example
    ///
    /// ```
    /// # use odra_core::CallDef;
    /// # use casper_types::RuntimeArgs;
    /// # use casper_types::U512;
    /// let call_def = CallDef::new("my_method", false, RuntimeArgs::new())
    ///     .with_amount(U512::from(100));
    /// ```
    pub fn with_amount(mut self, amount: U512) -> Self {
        self.amount = amount;
        self
    }

    /// Returns a reference to the entry point name of the `CallDef` instance.
    pub fn entry_point(&self) -> &str {
        &self.entry_point
    }

    /// Returns the attached value of the `CallDef` instance.
    pub fn amount(&self) -> U512 {
        self.amount
    }

    /// Returns a reference to the runtime arguments of the `CallDef` instance.
    pub fn args(&self) -> &RuntimeArgs {
        &self.args
    }

    /// Retrieves a value from the runtime arguments of the `CallDef` instance.
    ///
    /// # Arguments
    ///
    /// * `name` - The name of the value to retrieve.
    ///
    /// # Returns
    ///
    /// An `Option` containing the retrieved value, or `None` if the value does not exist or cannot be converted to the specified type.
    ///
    /// # Example
    ///
    /// ```
    /// # use odra_core::CallDef;
    /// # use casper_types::{CLTyped, bytesrepr::FromBytes, RuntimeArgs};
    /// let call_def = CallDef::new("my_method", false, RuntimeArgs::new());
    /// let value: Option<u32> = call_def.get("my_value");
    /// ```
    pub fn get<T: CLTyped + FromBytes>(&self, name: &str) -> Option<T> {
        self.args.get(name).and_then(|v| v.clone().into_t().ok())
    }

    /// Returns whether the call mutates the state.
    pub fn is_mut(&self) -> bool {
        self.is_mut
    }
}

#[cfg(test)]
mod test {
    use crate::CallDef;
    use casper_types::{runtime_args, RuntimeArgs};

    #[test]
    fn test_get_arg() {
        let args = runtime_args! {
            "my_value" => 42u32
        };
        let call_def = CallDef::new("my_method", false, args);
        let value: Option<u32> = call_def.get("my_value");
        assert_eq!(value, Some(42u32));

        let value: Option<u32> = call_def.get("your_value");
        assert_eq!(value, None);
    }

    #[test]
    fn test_is_mut() {
        let call_def = CallDef::new("my_method", false, RuntimeArgs::new());
        assert!(!call_def.is_mut());

        let call_def = CallDef::new("my_method", true, RuntimeArgs::new());
        assert!(call_def.is_mut());
    }
}