mls_rs/group/
exported_tree.rs1use alloc::{borrow::Cow, vec::Vec};
6use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize};
7
8use crate::{
9 client::MlsError,
10 tree_kem::{
11 leaf_node::LeafNode,
12 node::{LeafIndex, Node, NodeIndex, NodeVec, Parent},
13 },
14};
15
16use super::Roster;
17
18#[derive(Debug, MlsSize, MlsEncode, MlsDecode, PartialEq, Clone)]
19pub struct ExportedTree<'a>(pub(crate) Cow<'a, NodeVec>);
20
21impl<'a> ExportedTree<'a> {
22 pub(crate) fn new(node_data: NodeVec) -> Self {
23 Self(Cow::Owned(node_data))
24 }
25
26 pub(crate) fn new_borrowed(node_data: &'a NodeVec) -> Self {
27 Self(Cow::Borrowed(node_data))
28 }
29
30 pub fn to_bytes(&self) -> Result<Vec<u8>, MlsError> {
31 self.mls_encode_to_vec().map_err(Into::into)
32 }
33
34 pub fn byte_size(&self) -> usize {
35 self.mls_encoded_len()
36 }
37
38 pub fn into_owned(self) -> ExportedTree<'static> {
39 ExportedTree(Cow::Owned(self.0.into_owned()))
40 }
41
42 pub fn roster(&'a self) -> Roster<'a> {
43 Roster {
44 public_tree: &self.0,
45 }
46 }
47
48 pub fn nodes(&self) -> &[Option<Node>] {
54 &self.0
55 }
56
57 pub fn filtered_direct_path(&self, index: LeafIndex) -> Result<Vec<Option<&Parent>>, MlsError> {
65 let direct_copath = self.0.direct_copath(index);
66 let filtered = self.0.filtered(index)?;
67
68 let path = direct_copath
69 .into_iter()
70 .zip(filtered)
71 .filter_map(|(cp, is_filtered)| {
72 (!is_filtered).then(|| {
73 self.0
74 .get(cp.path as usize)
75 .and_then(Option::as_ref)
76 .and_then(|n| match n {
77 Node::Parent(p) => Some(p),
78 Node::Leaf(_) => None,
79 })
80 })
81 })
82 .collect();
83
84 Ok(path)
85 }
86
87 pub fn get_parent(&self, index: NodeIndex) -> Result<Option<&Parent>, MlsError> {
91 let parent = self.0.borrow_node(index)?.as_ref().and_then(|n| match n {
92 Node::Parent(p) => Some(p),
93 Node::Leaf(_) => None,
94 });
95
96 Ok(parent)
97 }
98
99 pub fn get_leaf(&self, index: LeafIndex) -> Result<Option<&LeafNode>, MlsError> {
102 let leaf = self
103 .0
104 .borrow_node(index.into())?
105 .as_ref()
106 .and_then(|n| match n {
107 Node::Leaf(l) => Some(l),
108 Node::Parent(_) => None,
109 });
110
111 Ok(leaf)
112 }
113}
114
115impl ExportedTree<'static> {
116 pub fn from_bytes(bytes: &[u8]) -> Result<Self, MlsError> {
117 Self::mls_decode(&mut &*bytes).map_err(Into::into)
118 }
119}
120
121impl From<ExportedTree<'_>> for NodeVec {
122 fn from(value: ExportedTree) -> Self {
123 value.0.into_owned()
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::tree_kem::node::{test_utils::get_test_node_vec, NodeTypeResolver};
131
132 #[maybe_async::test(not(mls_build_async), async(mls_build_async, crate::futures_test))]
133 async fn test_exported_tree_accessors() {
134 let nodes = get_test_node_vec().await;
151 let tree = ExportedTree::new(nodes.clone());
152
153 assert_eq!(tree.nodes().len(), nodes.len());
154
155 let leaf_a = tree.get_leaf(LeafIndex::unchecked(0)).unwrap().unwrap();
156 assert_eq!(leaf_a, nodes[0].as_leaf().unwrap());
157
158 let leaf_b = tree.get_leaf(LeafIndex::unchecked(1)).unwrap();
160 assert!(leaf_b.is_none());
161
162 let parent = tree.get_parent(5).unwrap().unwrap();
164 assert_eq!(parent, nodes[5].as_parent().unwrap());
165
166 let blank_parent = tree.get_parent(1).unwrap();
168 assert!(blank_parent.is_none());
169
170 let not_parent = tree.get_parent(0).unwrap();
172 assert!(not_parent.is_none());
173
174 let fdp = tree.filtered_direct_path(LeafIndex::unchecked(0)).unwrap();
180 assert_eq!(fdp.len(), 1);
181 assert!(fdp[0].is_none()); let fdp2 = tree.filtered_direct_path(LeafIndex::unchecked(2)).unwrap();
190 assert_eq!(fdp2.len(), 2);
191 assert_eq!(fdp2[0].unwrap().public_key.as_ref(), b"CD");
193 assert!(fdp2[1].is_none());
195 }
196}