homestar_invocation/
invocation.rs1use crate::{ipld::DagCbor, Error, Pointer, Task, Unit};
6use libipld::{serde::from_ipld, Ipld};
7use serde::{Deserialize, Serialize};
8use std::collections::BTreeMap;
9
10const TASK_KEY: &str = "task";
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct Invocation<'a, T> {
15 task: Task<'a, T>,
16}
17
18impl<'a, T> From<Task<'a, T>> for Invocation<'a, T>
19where
20 Ipld: From<T>,
21{
22 fn from(task: Task<'a, T>) -> Self {
23 Invocation::new(task)
24 }
25}
26
27impl<'a, T> Invocation<'a, T>
28where
29 Ipld: From<T>,
30{
31 pub fn new(task: Task<'a, T>) -> Self {
33 Self { task }
34 }
35}
36
37impl<T> From<Invocation<'_, T>> for Ipld
38where
39 Ipld: From<T>,
40{
41 fn from(invocation: Invocation<'_, T>) -> Self {
42 Ipld::Map(BTreeMap::from([(TASK_KEY.into(), invocation.task.into())]))
43 }
44}
45
46impl<T> TryFrom<Ipld> for Invocation<'_, T>
47where
48 T: From<Ipld>,
49{
50 type Error = Error<Unit>;
51
52 fn try_from(ipld: Ipld) -> Result<Self, Self::Error> {
53 let map = from_ipld::<BTreeMap<String, Ipld>>(ipld)?;
54
55 Ok(Self {
56 task: Task::try_from(
57 map.get(TASK_KEY)
58 .ok_or_else(|| Error::<Unit>::MissingField(TASK_KEY.to_string()))?
59 .to_owned(),
60 )?,
61 })
62 }
63}
64
65impl<T> TryFrom<Invocation<'_, T>> for Pointer
66where
67 Ipld: From<T>,
68{
69 type Error = Error<Unit>;
70
71 fn try_from(invocation: Invocation<'_, T>) -> Result<Self, Self::Error> {
72 Ok(Pointer::new(invocation.to_cid()?))
73 }
74}
75
76impl<'a, T> DagCbor for Invocation<'a, T> where Ipld: From<T> {}
77
78#[cfg(test)]
79mod test {
80 use super::*;
81 use crate::{
82 authority::UcanPrf,
83 task::{instruction::RunInstruction, Resources},
84 test_utils,
85 };
86
87 #[test]
88 fn ipld_roundtrip() {
89 let config = Resources::default();
90 let instruction = test_utils::instruction::<Unit>();
91 let task = Task::new(
92 RunInstruction::Expanded(instruction.clone()),
93 config.into(),
94 UcanPrf::default(),
95 );
96
97 let invocation = Invocation::new(task);
98 let ipld = Ipld::from(invocation.clone());
99 assert_eq!(invocation, Invocation::try_from(ipld).unwrap());
100 }
101
102 #[test]
103 fn ser_de() {
104 let config = Resources::default();
105 let instruction = test_utils::instruction::<Unit>();
106 let task = Task::new(
107 RunInstruction::Expanded(instruction.clone()),
108 config.into(),
109 UcanPrf::default(),
110 );
111 let invocation = Invocation::new(task);
112
113 let ser = serde_json::to_string(&invocation).unwrap();
114 let de = serde_json::from_str(&ser).unwrap();
115
116 assert_eq!(invocation, de);
117 }
118}