1use crate::cap::{Cap, SendCap};
36use crate::permission::*;
37
38pub trait Has<P: Permission> {
62 fn cap_ref(&self) -> Cap<P>;
64}
65
66impl<P: Permission> Has<P> for Cap<P> {
69 fn cap_ref(&self) -> Cap<P> {
70 Cap::new()
71 }
72}
73
74impl<P: Permission> Has<P> for SendCap<P> {
77 fn cap_ref(&self) -> Cap<P> {
78 self.as_cap()
79 }
80}
81
82macro_rules! impl_subsumes {
85 ($super:ty => $($sub:ty),+) => {
86 $(
87 impl Has<$sub> for Cap<$super> {
88 fn cap_ref(&self) -> Cap<$sub> { Cap::new() }
89 }
90 )+
91 }
92}
93
94impl_subsumes!(FsAll => FsRead, FsWrite);
95impl_subsumes!(NetAll => NetConnect, NetBind);
96
97macro_rules! impl_ambient {
104 ($($perm:ty),+) => {
105 $(
106 impl Has<$perm> for Cap<Ambient> {
107 fn cap_ref(&self) -> Cap<$perm> { Cap::new() }
108 }
109 )+
110 }
111}
112
113impl_ambient!(
116 FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn
117);
118
119macro_rules! impl_tuple_has_first {
130 ([$($a:ident),+]; $all:tt) => {
131 $( impl_tuple_has_first!(@inner $a; $all); )+
132 };
133 (@inner $a:ident; [$($b:ident),+]) => {
134 $(
135 impl Has<$a> for Cap<($a, $b)> {
136 fn cap_ref(&self) -> Cap<$a> { Cap::new() }
137 }
138 )+
139 };
140}
141
142macro_rules! impl_tuple_has_second {
143 ($first:ident $(, $rest:ident)+) => {
144 $(
145 impl Has<$first> for Cap<($rest, $first)> {
146 fn cap_ref(&self) -> Cap<$first> { Cap::new() }
147 }
148 impl Has<$rest> for Cap<($first, $rest)> {
149 fn cap_ref(&self) -> Cap<$rest> { Cap::new() }
150 }
151 )+
152 impl_tuple_has_second!($($rest),+);
153 };
154 ($single:ident) => {};
155}
156
157impl_tuple_has_first!(
158 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient];
159 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient]
160);
161
162impl_tuple_has_second!(
163 FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient
164);
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use crate::root::test_root;
170
171 #[test]
172 fn direct_cap_satisfies_has() {
173 let root = test_root();
174 let cap = root.grant::<FsRead>();
175 fn needs_fs(_: &impl Has<FsRead>) {}
176 needs_fs(&cap);
177 }
178
179 #[test]
180 fn fs_all_subsumes_read_and_write() {
181 let root = test_root();
182 let cap = root.grant::<FsAll>();
183 fn needs_read(_: &impl Has<FsRead>) {}
184 fn needs_write(_: &impl Has<FsWrite>) {}
185 needs_read(&cap);
186 needs_write(&cap);
187 }
188
189 #[test]
190 fn net_all_subsumes_connect_and_bind() {
191 let root = test_root();
192 let cap = root.grant::<NetAll>();
193 fn needs_connect(_: &impl Has<NetConnect>) {}
194 fn needs_bind(_: &impl Has<NetBind>) {}
195 needs_connect(&cap);
196 needs_bind(&cap);
197 }
198
199 #[test]
200 fn ambient_satisfies_anything() {
201 let root = test_root();
202 let cap = root.grant::<Ambient>();
203 fn needs_fs(_: &impl Has<FsRead>) {}
204 fn needs_net(_: &impl Has<NetConnect>) {}
205 fn needs_spawn(_: &impl Has<Spawn>) {}
206 needs_fs(&cap);
207 needs_net(&cap);
208 needs_spawn(&cap);
209 }
210
211 #[test]
212 fn multiple_cap_params() {
213 fn sync_data(_fs: &impl Has<FsRead>, _net: &impl Has<NetConnect>) {}
214 let root = test_root();
215 let fs = root.grant::<FsRead>();
216 let net = root.grant::<NetConnect>();
217 sync_data(&fs, &net);
218 }
219
220 #[test]
221 fn tuple_cap_satisfies_both_has() {
222 let root = test_root();
223 let cap = root.grant::<(FsRead, NetConnect)>();
224 fn needs_fs(_: &impl Has<FsRead>) {}
225 fn needs_net(_: &impl Has<NetConnect>) {}
226 needs_fs(&cap);
227 needs_net(&cap);
228 }
229
230 #[test]
231 fn tuple_self_pair() {
232 let root = test_root();
233 let cap = root.grant::<(FsRead, FsRead)>();
234 fn needs_fs(_: &impl Has<FsRead>) {}
235 needs_fs(&cap);
236 }
237
238 #[test]
239 fn tuple_with_subsumption_type() {
240 let root = test_root();
241 let cap = root.grant::<(FsAll, NetConnect)>();
242 fn needs_fs_all(_: &impl Has<FsAll>) {}
243 fn needs_net(_: &impl Has<NetConnect>) {}
244 needs_fs_all(&cap);
245 needs_net(&cap);
246 }
247
248 #[test]
249 fn tuple_cap_ref_returns_correct_type() {
250 let root = test_root();
251 let cap = root.grant::<(FsRead, NetConnect)>();
252 let _fs: Cap<FsRead> = Has::<FsRead>::cap_ref(&cap);
253 let _net: Cap<NetConnect> = Has::<NetConnect>::cap_ref(&cap);
254 }
255
256 #[test]
257 fn tuple_is_zst() {
258 use std::mem::size_of;
259 assert_eq!(size_of::<Cap<(FsRead, NetConnect)>>(), 0);
260 }
261
262 #[test]
266 fn ambient_covers_all_permissions() {
267 fn assert_ambient_has<P: Permission>()
268 where
269 Cap<Ambient>: Has<P>,
270 {
271 }
272
273 assert_ambient_has::<FsRead>();
274 assert_ambient_has::<FsWrite>();
275 assert_ambient_has::<FsAll>();
276 assert_ambient_has::<NetConnect>();
277 assert_ambient_has::<NetBind>();
278 assert_ambient_has::<NetAll>();
279 assert_ambient_has::<EnvRead>();
280 assert_ambient_has::<EnvWrite>();
281 assert_ambient_has::<Spawn>();
282 }
284}