rkyv/ser/sharing/
alloc.rs1use core::{error::Error, fmt, hash::BuildHasherDefault};
2
3use hashbrown::hash_map::{Entry, HashMap};
4use rancor::{fail, Source};
5
6use crate::{
7 hash::FxHasher64,
8 ser::{sharing::SharingState, Sharing},
9};
10
11#[derive(Debug, Default)]
14pub struct Share {
15 shared_address_to_pos:
16 HashMap<usize, Option<usize>, BuildHasherDefault<FxHasher64>>,
17}
18
19impl Share {
20 #[inline]
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 #[inline]
28 pub fn with_capacity(capacity: usize) -> Self {
29 Self {
30 shared_address_to_pos: HashMap::with_capacity_and_hasher(
31 capacity,
32 Default::default(),
33 ),
34 }
35 }
36
37 pub fn clear(&mut self) {
39 self.shared_address_to_pos.clear();
40 }
41}
42
43#[derive(Debug)]
44struct NotStarted;
45
46impl fmt::Display for NotStarted {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 write!(f, "shared pointer was not started sharing")
49 }
50}
51
52impl Error for NotStarted {}
53
54#[derive(Debug)]
55struct AlreadyFinished;
56
57impl fmt::Display for AlreadyFinished {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 write!(f, "shared pointer was already finished sharing")
60 }
61}
62
63impl Error for AlreadyFinished {}
64
65impl<E: Source> Sharing<E> for Share {
66 fn start_sharing(&mut self, address: usize) -> SharingState {
67 match self.shared_address_to_pos.entry(address) {
68 Entry::Vacant(vacant) => {
69 vacant.insert(None);
70 SharingState::Started
71 }
72 Entry::Occupied(occupied) => {
73 if let Some(pos) = occupied.get() {
74 SharingState::Finished(*pos)
75 } else {
76 SharingState::Pending
77 }
78 }
79 }
80 }
81
82 fn finish_sharing(&mut self, address: usize, pos: usize) -> Result<(), E> {
83 match self.shared_address_to_pos.entry(address) {
84 Entry::Vacant(_) => fail!(NotStarted),
85 Entry::Occupied(mut occupied) => {
86 let inner = occupied.get_mut();
87 if inner.is_some() {
88 fail!(AlreadyFinished);
89 } else {
90 *inner = Some(pos);
91 Ok(())
92 }
93 }
94 }
95 }
96}