1use std::{pin::Pin, sync::Arc};
2
3mod arc;
4mod option;
5
6#[cfg(feature = "async-graphql")]
7pub mod graphql;
8
9pub use arc::ArcProject;
10pub use option::ArcProjectOption;
11
12pub trait ArcExt<T: ?Sized>: Unpin
13where
14 T: Unpin,
15{
16 fn project<'a, 'b, U, F>(self, deref_fn: F) -> ArcProject<'a, 'b, T, U>
17 where
18 'a: 'b,
19 T: 'a,
20 U: 'b,
21 F: Fn(&'a Pin<Arc<T>>) -> &'b U;
22
23 fn project_option<'a, 'b, U, F>(self, deref_fn: F) -> ArcProjectOption<'a, 'b, T, U>
24 where
25 'a: 'b,
26 T: 'a,
27 U: 'b,
28 F: Fn(&'a Pin<Arc<T>>) -> Option<&'b U>;
29}
30
31impl<T: ?Sized + Unpin> ArcExt<T> for Arc<T> {
32 fn project<'a, 'b, U, F>(self, deref_fn: F) -> ArcProject<'a, 'b, T, U>
33 where
34 'a: 'b,
35 T: 'a,
36 U: 'b,
37 F: Fn(&'a Pin<Arc<T>>) -> &'b U,
38 {
39 ArcProject::new(self, deref_fn)
40 }
41
42 fn project_option<'a, 'b, U, F>(self, deref_fn: F) -> ArcProjectOption<'a, 'b, T, U>
43 where
44 'a: 'b,
45 T: 'a,
46 U: 'b,
47 F: Fn(&'a Pin<Arc<T>>) -> Option<&'b U>,
48 {
49 ArcProjectOption::new(self, deref_fn)
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[derive(Debug, PartialEq, Eq)]
58 struct Top {
59 nested: Nested,
60 string: String,
61 }
62
63 #[derive(Debug, PartialEq, Eq)]
64 struct Nested {
65 a: u32,
66 b: Box<[u8]>,
67 c: Option<Arc<Top>>,
68 }
69
70 #[test]
71 fn test() {
72 let top = Arc::new(Top {
73 nested: Nested {
74 a: 32,
75 b: vec![1, 2, 3, 4].into_boxed_slice(),
76 c: Some(Arc::new(Top {
77 nested: Nested {
78 a: 12,
79 b: vec![99].into_boxed_slice(),
80 c: None,
81 },
82 string: "nested".to_string(),
83 })),
84 },
85 string: "owned str".to_string(),
86 });
87
88 let project = top.clone().project(|x| &x.nested.b);
89 assert_eq!(&[1, 2, 3, 4], &**project);
90 drop(project);
91
92 let project = top.clone().project_option(|x| x.nested.c.as_ref());
93 let opt = project.as_option().unwrap();
94
95 assert_eq!(top.nested.c.as_ref().unwrap(), opt);
96 }
97}