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!(
164 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient];
165 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient]
166);
167
168impl_tuple_has_second!(
169 FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient
170);
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175 use crate::root::test_root;
176
177 #[test]
178 fn direct_cap_satisfies_has() {
179 let root = test_root();
180 let cap = root.grant::<FsRead>();
181 fn needs_fs(_: &impl Has<FsRead>) {}
182 needs_fs(&cap);
183 }
184
185 #[test]
186 fn fs_all_subsumes_read_and_write() {
187 let root = test_root();
188 let cap = root.grant::<FsAll>();
189 fn needs_read(_: &impl Has<FsRead>) {}
190 fn needs_write(_: &impl Has<FsWrite>) {}
191 needs_read(&cap);
192 needs_write(&cap);
193 }
194
195 #[test]
196 fn net_all_subsumes_connect_and_bind() {
197 let root = test_root();
198 let cap = root.grant::<NetAll>();
199 fn needs_connect(_: &impl Has<NetConnect>) {}
200 fn needs_bind(_: &impl Has<NetBind>) {}
201 needs_connect(&cap);
202 needs_bind(&cap);
203 }
204
205 #[test]
206 fn ambient_satisfies_anything() {
207 let root = test_root();
208 let cap = root.grant::<Ambient>();
209 fn needs_fs(_: &impl Has<FsRead>) {}
210 fn needs_net(_: &impl Has<NetConnect>) {}
211 fn needs_spawn(_: &impl Has<Spawn>) {}
212 needs_fs(&cap);
213 needs_net(&cap);
214 needs_spawn(&cap);
215 }
216
217 #[test]
218 fn multiple_cap_params() {
219 fn sync_data(_fs: &impl Has<FsRead>, _net: &impl Has<NetConnect>) {}
220 let root = test_root();
221 let fs = root.grant::<FsRead>();
222 let net = root.grant::<NetConnect>();
223 sync_data(&fs, &net);
224 }
225
226 #[test]
227 fn tuple_cap_satisfies_both_has() {
228 let root = test_root();
229 let cap = root.grant::<(FsRead, NetConnect)>();
230 fn needs_fs(_: &impl Has<FsRead>) {}
231 fn needs_net(_: &impl Has<NetConnect>) {}
232 needs_fs(&cap);
233 needs_net(&cap);
234 }
235
236 #[test]
237 fn tuple_self_pair() {
238 let root = test_root();
239 let cap = root.grant::<(FsRead, FsRead)>();
240 fn needs_fs(_: &impl Has<FsRead>) {}
241 needs_fs(&cap);
242 }
243
244 #[test]
245 fn tuple_with_subsumption_type() {
246 let root = test_root();
247 let cap = root.grant::<(FsAll, NetConnect)>();
248 fn needs_fs_all(_: &impl Has<FsAll>) {}
249 fn needs_net(_: &impl Has<NetConnect>) {}
250 needs_fs_all(&cap);
251 needs_net(&cap);
252 }
253
254 #[test]
255 fn tuple_cap_ref_returns_correct_type() {
256 let root = test_root();
257 let cap = root.grant::<(FsRead, NetConnect)>();
258 let _fs: Cap<FsRead> = Has::<FsRead>::cap_ref(&cap);
259 let _net: Cap<NetConnect> = Has::<NetConnect>::cap_ref(&cap);
260 }
261
262 #[test]
263 fn tuple_is_zst() {
264 use std::mem::size_of;
265 assert_eq!(size_of::<Cap<(FsRead, NetConnect)>>(), 0);
266 }
267
268 #[test]
272 fn ambient_covers_all_permissions() {
273 fn assert_ambient_has<P: Permission>()
274 where
275 Cap<Ambient>: Has<P>,
276 {
277 }
278
279 assert_ambient_has::<FsRead>();
280 assert_ambient_has::<FsWrite>();
281 assert_ambient_has::<FsAll>();
282 assert_ambient_has::<NetConnect>();
283 assert_ambient_has::<NetBind>();
284 assert_ambient_has::<NetAll>();
285 assert_ambient_has::<EnvRead>();
286 assert_ambient_has::<EnvWrite>();
287 assert_ambient_has::<Spawn>();
288 }
290}