1use crate::{invalid, MAX_MEMORY_BYTES};
2use std::io;
3use std::ops::Deref;
4use std::sync::atomic::{AtomicUsize, Ordering};
5use std::sync::Arc;
6
7#[derive(Clone, Debug)]
8pub(crate) struct Budget(Arc<AtomicUsize>);
9impl Budget {
10 #[cfg(any(feature = "server", test))]
11 pub(crate) fn new() -> Self {
12 Self(Arc::new(AtomicUsize::new(0)))
13 }
14 pub(crate) fn reserve(&self, bytes: usize) -> io::Result<Permit> {
15 self.0
16 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| {
17 old.checked_add(bytes)
18 .filter(|next| *next <= MAX_MEMORY_BYTES)
19 })
20 .map_err(|_| invalid("native window aggregate memory exhausted"))?;
21 Ok(Permit {
22 budget: self.clone(),
23 bytes,
24 })
25 }
26 #[cfg(any(feature = "server", test))]
27 pub(crate) fn used(&self) -> usize {
28 self.0.load(Ordering::Acquire)
29 }
30}
31#[derive(Debug)]
32pub(crate) struct Permit {
33 budget: Budget,
34 bytes: usize,
35}
36impl Drop for Permit {
37 fn drop(&mut self) {
38 self.budget.0.fetch_sub(self.bytes, Ordering::AcqRel);
39 }
40}
41
42#[derive(Debug)]
43struct Payload {
44 bytes: Vec<u8>,
45 offset: usize,
46 _permit: Option<Permit>,
47}
48#[derive(Clone, Debug)]
51pub struct PixelBuffer(Arc<Payload>);
52impl PixelBuffer {
53 pub fn new(bytes: Vec<u8>) -> Self {
54 Self(Arc::new(Payload {
55 bytes,
56 offset: 0,
57 _permit: None,
58 }))
59 }
60 pub(crate) fn received(bytes: Vec<u8>, offset: usize, permit: Option<Permit>) -> Self {
61 Self(Arc::new(Payload {
62 bytes,
63 offset,
64 _permit: permit,
65 }))
66 }
67}
68impl From<Vec<u8>> for PixelBuffer {
69 fn from(bytes: Vec<u8>) -> Self {
70 Self::new(bytes)
71 }
72}
73impl Deref for PixelBuffer {
74 type Target = [u8];
75 fn deref(&self) -> &[u8] {
76 &self.0.bytes[self.0.offset..]
77 }
78}
79impl AsRef<[u8]> for PixelBuffer {
80 fn as_ref(&self) -> &[u8] {
81 self
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 #[test]
89 fn permit_follows_shared_pixels_and_releases_only_at_last_owner() {
90 let budget = Budget::new();
91 let permit = budget.reserve(28).unwrap();
92 let pixels = PixelBuffer::received(vec![0; 28], 24, Some(permit));
93 let adopted = pixels.clone();
94 drop(pixels);
95 assert_eq!(budget.used(), 28);
96 assert_eq!(adopted.len(), 4);
97 drop(adopted);
98 assert_eq!(budget.used(), 0);
99 }
100 #[test]
101 fn aggregate_reservation_fails_before_allocation_and_recovers() {
102 let budget = Budget::new();
103 let permit = budget.reserve(MAX_MEMORY_BYTES).unwrap();
104 assert!(budget.reserve(1).is_err());
105 assert_eq!(budget.used(), MAX_MEMORY_BYTES);
106 drop(permit);
107 assert_eq!(budget.reserve(1).unwrap().bytes, 1);
108 assert_eq!(budget.used(), 0);
109 }
110}