homestar_invocation/task/
config.rs1use crate::{consts, Error, Unit};
6use libipld::{serde::from_ipld, Ipld};
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use std::{collections::BTreeMap, time::Duration};
10
11const FUEL_KEY: &str = "fuel";
12const MEMORY_KEY: &str = "memory";
13const TIMEOUT_KEY: &str = "time";
14
15#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
17#[schemars(
18 rename = "resources",
19 description = "Resource configuration for fuel quota, memory allowance, and timeout"
20)]
21pub struct Resources {
22 fuel: Option<u64>,
23 #[schemars(description = "Memory in bytes")]
24 memory: Option<u64>,
25 #[schemars(with = "Option<u64>", description = "Timeout in milliseconds")]
26 time: Option<Duration>,
27}
28
29impl Default for Resources {
30 fn default() -> Self {
31 Self {
32 fuel: Some(u64::MAX),
33 memory: Some(consts::WASM_MAX_MEMORY),
34 time: Some(Duration::from_millis(100_000)),
35 }
36 }
37}
38
39impl Resources {
40 pub fn new(fuel: u64, memory: u64, time: Duration) -> Self {
42 Self {
43 fuel: Some(fuel),
44 memory: Some(memory),
45 time: Some(time),
46 }
47 }
48
49 pub fn fuel(&self) -> Option<u64> {
51 self.fuel
52 }
53
54 pub fn set_fuel(&mut self, fuel: u64) {
56 self.fuel = Some(fuel)
57 }
58
59 pub fn time(&self) -> Option<Duration> {
61 self.time
62 }
63
64 pub fn set_time(&mut self, time: Duration) {
66 self.time = Some(time)
67 }
68
69 pub fn memory(&self) -> Option<u64> {
71 self.memory
72 }
73
74 pub fn set_memory(&mut self, memory: u64) {
76 self.memory = Some(memory)
77 }
78}
79
80impl From<Resources> for Ipld {
81 fn from(resources: Resources) -> Ipld {
82 Ipld::Map(BTreeMap::from([
83 (
84 FUEL_KEY.into(),
85 resources.fuel().map(Ipld::from).unwrap_or(Ipld::Null),
86 ),
87 (
88 MEMORY_KEY.into(),
89 resources.memory().map(Ipld::from).unwrap_or(Ipld::Null),
90 ),
91 (
92 TIMEOUT_KEY.into(),
93 resources
94 .time()
95 .map(|t| Ipld::from(t.as_millis() as i128))
96 .unwrap_or(Ipld::Null),
97 ),
98 ]))
99 }
100}
101
102impl<'a> TryFrom<&'a Ipld> for Resources {
103 type Error = Error<Unit>;
104
105 fn try_from(ipld: &Ipld) -> Result<Self, Self::Error> {
106 Resources::try_from(ipld.to_owned())
107 }
108}
109
110impl TryFrom<Ipld> for Resources {
111 type Error = Error<Unit>;
112
113 fn try_from(ipld: Ipld) -> Result<Self, Self::Error> {
114 let map = from_ipld::<BTreeMap<String, Ipld>>(ipld)?;
115
116 let fuel = map.get(FUEL_KEY).and_then(|ipld| match ipld {
117 Ipld::Null => None,
118 ipld => from_ipld(ipld.to_owned()).ok(),
119 });
120
121 let memory = map.get(MEMORY_KEY).and_then(|ipld| match ipld {
122 Ipld::Null => None,
123 ipld => from_ipld(ipld.to_owned()).ok(),
124 });
125
126 let time = map.get(TIMEOUT_KEY).and_then(|ipld| match ipld {
127 Ipld::Null => None,
128 ipld => {
129 let time = from_ipld(ipld.to_owned()).unwrap_or(100_000);
130 Some(Duration::from_millis(time))
131 }
132 });
133
134 Ok(Resources { fuel, memory, time })
135 }
136}
137
138#[cfg(test)]
139mod test {
140 use super::*;
141
142 #[test]
143 fn ipld_roundtrip() {
144 let config = Resources::default();
145 let ipld = Ipld::from(config.clone());
146
147 assert_eq!(
148 ipld,
149 Ipld::Map(BTreeMap::from([
150 (FUEL_KEY.into(), Ipld::Integer(u64::MAX.into())),
151 (
152 MEMORY_KEY.into(),
153 Ipld::Integer(consts::WASM_MAX_MEMORY.into())
154 ),
155 (TIMEOUT_KEY.into(), Ipld::Integer(100_000))
156 ]))
157 );
158 assert_eq!(config, ipld.try_into().unwrap())
159 }
160
161 #[test]
162 fn ser_de() {
163 let config = Resources::default();
164 let ser = serde_json::to_string(&config).unwrap();
165 let de = serde_json::from_str(&ser).unwrap();
166
167 assert_eq!(config, de);
168 }
169}