dope_core/driver/
route.rs1use std::cell::Cell;
2use std::io::{self, Error, ErrorKind};
3
4use crate::driver::control::ContextControl;
5
6use super::token::ROUTE_FRAMEWORK;
7use super::{DriverContext, DriverRef};
8
9pub(crate) struct Routes {
10 live: [u64; 4],
11 poisoned: [u64; 4],
12}
13
14impl Routes {
15 pub(crate) const fn new() -> Self {
16 Self {
17 live: [0; 4],
18 poisoned: [0; 4],
19 }
20 }
21
22 pub(crate) fn reserve(&mut self, id: u8) -> bool {
23 let word = id as usize / 64;
24 let mask = 1u64 << (id % 64);
25 if self.live[word] & mask != 0 || self.poisoned[word] & mask != 0 {
26 return false;
27 }
28 self.live[word] |= mask;
29 true
30 }
31
32 pub(crate) fn release(&mut self, id: u8) {
33 self.live[id as usize / 64] &= !(1u64 << (id % 64));
34 }
35
36 pub(crate) fn poison(&mut self, id: u8) {
37 debug_assert!(!self.is_poisoned(id));
38 let word = id as usize / 64;
39 let mask = 1u64 << (id % 64);
40 self.live[word] &= !mask;
41 self.poisoned[word] |= mask;
42 }
43
44 pub(crate) fn is_poisoned(&self, id: u8) -> bool {
45 self.poisoned[id as usize / 64] & (1u64 << (id % 64)) != 0
46 }
47}
48
49pub struct Route<'d, const ID: u8> {
50 driver: DriverRef<'d>,
51 live: Cell<bool>,
52}
53
54#[doc(hidden)]
55pub struct RouteReservation<'a, 'c, 'd, const ID: u8> {
56 route: Option<Route<'d, ID>>,
57 driver: &'a mut DriverContext<'c, 'd>,
58}
59
60impl<'d, const ID: u8> Route<'d, ID> {
61 pub fn reserve(driver: &mut DriverContext<'_, 'd>) -> io::Result<Self> {
62 if ID == ROUTE_FRAMEWORK {
63 return Err(Error::new(ErrorKind::InvalidInput, "dope: reserved route"));
64 }
65 if !driver.reserve_route(ID) {
66 return Err(Error::new(
67 ErrorKind::AlreadyExists,
68 "dope: route already used",
69 ));
70 }
71 Ok(Self {
72 driver: driver.driver_ref(),
73 live: Cell::new(true),
74 })
75 }
76
77 #[doc(hidden)]
78 pub fn reserve_transaction<'a, 'c>(
79 driver: &'a mut DriverContext<'c, 'd>,
80 ) -> io::Result<RouteReservation<'a, 'c, 'd, ID>> {
81 let route = Self::reserve(driver)?;
82 Ok(RouteReservation {
83 route: Some(route),
84 driver,
85 })
86 }
87
88 pub fn poison(&self, driver: &mut DriverContext<'_, 'd>) {
89 if self.live.replace(false) {
90 driver.poison_route(ID);
91 }
92 }
93
94 pub fn driver(&self) -> DriverRef<'d> {
95 self.driver
96 }
97
98 pub fn release(self, driver: &mut DriverContext<'_, 'd>) {
99 if self.live.replace(false) {
100 driver.release_route(ID);
101 }
102 }
103
104 pub fn finish(&self, driver: &mut DriverContext<'_, 'd>, poison: bool) {
105 if !self.live.replace(false) {
106 return;
107 }
108 if poison {
109 driver.poison_route(ID);
110 } else {
111 driver.release_route(ID);
112 }
113 }
114}
115
116impl<'c, 'd, const ID: u8> RouteReservation<'_, 'c, 'd, ID> {
117 pub fn driver(&mut self) -> &mut DriverContext<'c, 'd> {
118 self.driver
119 }
120
121 pub fn commit(mut self) -> Route<'d, ID> {
122 let Some(route) = self.route.take() else {
123 unreachable!("dope: route reservation committed twice")
124 };
125 route
126 }
127}
128
129impl<const ID: u8> Drop for RouteReservation<'_, '_, '_, ID> {
130 fn drop(&mut self) {
131 if let Some(route) = self.route.take() {
132 route.release(self.driver);
133 }
134 }
135}