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
54impl<'d, const ID: u8> Route<'d, ID> {
55 pub fn reserve(driver: &mut DriverContext<'_, 'd>) -> io::Result<Self> {
56 if ID == ROUTE_FRAMEWORK {
57 return Err(Error::new(ErrorKind::InvalidInput, "dope: reserved route"));
58 }
59 if !driver.reserve_route(ID) {
60 return Err(Error::new(
61 ErrorKind::AlreadyExists,
62 "dope: route already used",
63 ));
64 }
65 Ok(Self {
66 driver: driver.driver_ref(),
67 live: Cell::new(true),
68 })
69 }
70
71 pub fn poison(&self, driver: &mut DriverContext<'_, 'd>) {
72 if self.live.replace(false) {
73 driver.poison_route(ID);
74 }
75 }
76
77 pub fn driver(&self) -> DriverRef<'d> {
78 self.driver
79 }
80
81 pub fn release(self, driver: &mut DriverContext<'_, 'd>) {
82 if self.live.replace(false) {
83 driver.release_route(ID);
84 }
85 }
86
87 pub fn finish(&self, driver: &mut DriverContext<'_, 'd>, poison: bool) {
88 if !self.live.replace(false) {
89 return;
90 }
91 if poison {
92 driver.poison_route(ID);
93 } else {
94 driver.release_route(ID);
95 }
96 }
97}