1use std::{
2 marker::PhantomData,
3 sync::{Arc, RwLock},
4};
5
6use crossbeam_queue::SegQueue;
7
8use crate::{
9 error::Error,
10 frame::{Frame, SharedFrame, SharedFrameInner},
11 FrameDescriptorSpec, Result,
12};
13
14pub trait FrameCreator<D: FrameDescriptorSpec>: Send + Sync {
15 fn create_frame(&self, desc: D) -> Result<Frame<'static, D>>;
16}
17
18pub type GenericFrameCreator<D> = dyn FrameCreator<D>;
19
20pub struct DefaultFrameCreator<D: FrameDescriptorSpec> {
21 _phantom: PhantomData<D>,
22}
23
24impl<D: FrameDescriptorSpec> Default for DefaultFrameCreator<D> {
25 fn default() -> Self {
26 Self {
27 _phantom: PhantomData,
28 }
29 }
30}
31
32impl<D: FrameDescriptorSpec> FrameCreator<D> for DefaultFrameCreator<D> {
33 fn create_frame(&self, desc: D) -> Result<Frame<'static, D>> {
34 desc.create_frame()
35 }
36}
37
38impl<D: FrameDescriptorSpec> From<DefaultFrameCreator<D>> for Arc<dyn FrameCreator<D>>
39where
40 DefaultFrameCreator<D>: FrameCreator<D>,
41{
42 fn from(creator: DefaultFrameCreator<D>) -> Self {
43 Arc::new(creator)
44 }
45}
46
47pub struct FramePoolConfig<D: FrameDescriptorSpec> {
48 pub desc: Option<D>,
49 pub creator: Arc<dyn FrameCreator<D>>,
50}
51
52pub struct FramePool<F: SharedFrameInner = RwLock<Frame<'static>>> {
53 queue: SegQueue<SharedFrame<F>>,
54 config: Arc<RwLock<FramePoolConfig<F::Descriptor>>>,
55}
56
57impl<F: SharedFrameInner> FramePool<F> {
58 pub fn new() -> Arc<Self>
59 where
60 DefaultFrameCreator<F::Descriptor>: FrameCreator<F::Descriptor>,
61 {
62 Arc::new(Self {
63 queue: SegQueue::new(),
64 config: Arc::new(RwLock::new(FramePoolConfig {
65 desc: None,
66 creator: DefaultFrameCreator::<F::Descriptor>::default().into(),
67 })),
68 })
69 }
70
71 pub fn new_with_creator(desc: F::Descriptor, creator: Box<GenericFrameCreator<F::Descriptor>>) -> Arc<Self> {
72 Arc::new(Self {
73 queue: SegQueue::new(),
74 config: Arc::new(RwLock::new(FramePoolConfig {
75 desc: Some(desc),
76 creator: Arc::from(creator),
77 })),
78 })
79 }
80
81 pub fn available(&self) -> usize {
82 self.queue.len()
83 }
84
85 pub fn configure(&self, desc: Option<F::Descriptor>, creator: Option<Box<GenericFrameCreator<F::Descriptor>>>) {
86 let need_clear = {
87 let mut config = self.config.write().unwrap();
88
89 let desc_changed = desc.is_some_and(|desc| {
90 if config.desc.as_ref() != Some(&desc) {
91 config.desc = Some(desc);
92 true
93 } else {
94 false
95 }
96 });
97
98 let creator_changed = creator.is_some_and(|creator| {
99 config.creator = Arc::from(creator);
100 true
101 });
102
103 desc_changed || creator_changed
104 };
105
106 if need_clear {
107 self.clear();
108 }
109 }
110
111 pub fn recycle_frame(&self, frame: SharedFrame<F>) {
112 self.queue.push(frame);
113 }
114
115 fn clear(&self) {
116 while self.queue.pop().is_some() {}
117 }
118
119 fn get_frame_internal<G, N>(self: &Arc<Self>, get_frame_desc: G, new_shared_frame: N) -> Result<SharedFrame<F>>
120 where
121 G: Fn(&SharedFrame<F>) -> F::Descriptor,
122 N: Fn(Frame<'static, F::Descriptor>) -> SharedFrame<F>,
123 {
124 let (desc, creator) = {
125 let config = self.config.read().unwrap();
126
127 if let Some(desc) = config.desc.clone() {
128 (desc, config.creator.clone())
129 } else {
130 return Err(Error::Invalid("frame descriptor".to_string()));
131 }
132 };
133
134 if let Some(mut frame) = self.queue.pop() {
135 if get_frame_desc(&frame) == desc {
136 frame.pool = Some(Arc::downgrade(self));
137 return Ok(frame);
138 }
139 }
140
141 let frame = creator.create_frame(desc)?;
142 let mut shared_frame = new_shared_frame(frame);
143 shared_frame.pool = Some(Arc::downgrade(self));
144
145 Ok(shared_frame)
146 }
147
148 fn set_frame_descriptor(&self, desc: F::Descriptor) {
149 let need_update = { self.config.read().unwrap().desc.as_ref() != Some(&desc) };
150
151 if need_update {
152 self.config.write().unwrap().desc = Some(desc);
153 self.clear();
154 }
155 }
156}
157
158impl<D: FrameDescriptorSpec> FramePool<RwLock<Frame<'static, D>>> {
159 pub fn get_frame(self: &Arc<Self>) -> Result<SharedFrame<RwLock<Frame<'static, D>>>> {
160 self.get_frame_internal(
161 |shared_frame| shared_frame.read().unwrap().desc.clone(),
162 |frame| SharedFrame::<RwLock<Frame<'static, D>>>::new(frame),
163 )
164 }
165
166 pub fn get_frame_with_descriptor(self: &Arc<Self>, desc: D) -> Result<SharedFrame<RwLock<Frame<'static, D>>>> {
167 self.set_frame_descriptor(desc);
168 self.get_frame()
169 }
170}
171
172impl<D: FrameDescriptorSpec> FramePool<Frame<'static, D>> {
173 pub fn get_frame(self: &Arc<Self>) -> Result<SharedFrame<Frame<'static, D>>> {
174 self.get_frame_internal(|shared_frame| shared_frame.read().desc.clone(), |frame| SharedFrame::<Frame<'static, D>>::new(frame))
175 }
176
177 pub fn get_frame_with_descriptor(self: &Arc<Self>, desc: D) -> Result<SharedFrame<Frame<'static, D>>> {
178 self.set_frame_descriptor(desc);
179 self.get_frame()
180 }
181}