Skip to main content

dope_core/driver/
route.rs

1use 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}