zenoh_sync/
object_pool.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//
// Copyright (c) 2023 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
//
// Contributors:
//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
//
use std::{
    any::Any,
    fmt,
    ops::{Deref, DerefMut, Drop},
    sync::{Arc, Weak},
};

use zenoh_buffers::ZSliceBuffer;

use super::LifoQueue;

/// Provides a pool of pre-allocated objects that are automaticlaly reinserted into
/// the pool when dropped.
pub struct RecyclingObjectPool<T, F>
where
    F: Fn() -> T,
{
    inner: Arc<LifoQueue<T>>,
    f: F,
}

impl<T, F: Fn() -> T> RecyclingObjectPool<T, F> {
    pub fn new(num: usize, f: F) -> RecyclingObjectPool<T, F> {
        let inner: Arc<LifoQueue<T>> = Arc::new(LifoQueue::new(num));
        for _ in 0..num {
            let obj = (f)();
            inner.try_push(obj);
        }
        RecyclingObjectPool { inner, f }
    }

    pub fn alloc(&self) -> RecyclingObject<T> {
        RecyclingObject::new((self.f)(), Weak::new())
    }

    pub fn try_take(&self) -> Option<RecyclingObject<T>> {
        self.inner
            .try_pull()
            .map(|obj| RecyclingObject::new(obj, Arc::downgrade(&self.inner)))
    }

    pub fn take(&self) -> RecyclingObject<T> {
        let obj = self.inner.pull();
        RecyclingObject::new(obj, Arc::downgrade(&self.inner))
    }
}

#[derive(Clone)]
pub struct RecyclingObject<T> {
    pool: Weak<LifoQueue<T>>,
    object: Option<T>,
}

impl<T> RecyclingObject<T> {
    pub fn new(obj: T, pool: Weak<LifoQueue<T>>) -> RecyclingObject<T> {
        RecyclingObject {
            pool,
            object: Some(obj),
        }
    }

    pub fn recycle(mut self) {
        if let Some(pool) = self.pool.upgrade() {
            if let Some(obj) = self.object.take() {
                pool.push(obj);
            }
        }
    }
}

impl<T: PartialEq> Eq for RecyclingObject<T> {}

impl<T: PartialEq> PartialEq for RecyclingObject<T> {
    fn eq(&self, other: &Self) -> bool {
        self.object == other.object
    }
}

impl<T> Deref for RecyclingObject<T> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &Self::Target {
        self.object.as_ref().unwrap()
    }
}

impl<T> DerefMut for RecyclingObject<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.object.as_mut().unwrap()
    }
}

impl<T> From<T> for RecyclingObject<T> {
    fn from(obj: T) -> RecyclingObject<T> {
        RecyclingObject::new(obj, Weak::new())
    }
}

impl<T> Drop for RecyclingObject<T> {
    fn drop(&mut self) {
        if let Some(pool) = self.pool.upgrade() {
            if let Some(obj) = self.object.take() {
                pool.push(obj);
            }
        }
    }
}

impl<T: fmt::Debug> fmt::Debug for RecyclingObject<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("").field("inner", &self.object).finish()
    }
}

// Buffer impl
impl AsRef<[u8]> for RecyclingObject<Box<[u8]>> {
    fn as_ref(&self) -> &[u8] {
        self.deref()
    }
}

impl AsMut<[u8]> for RecyclingObject<Box<[u8]>> {
    fn as_mut(&mut self) -> &mut [u8] {
        self.deref_mut()
    }
}

impl ZSliceBuffer for RecyclingObject<Box<[u8]>> {
    fn as_slice(&self) -> &[u8] {
        self.as_ref()
    }

    fn as_any(&self) -> &dyn Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}