cartel-sqlite 0.22.0

SQLite driver for the dope runtime
Documentation
use crate::limits;
use std::{cell, mem};

pub(crate) struct Meter {
    primary: Counter,
    mode: cell::Cell<Mode>,
    permission: cell::Cell<Permission>,
}

#[derive(Clone, Copy)]
pub(super) enum Permission {
    Denied,
    Granted,
}

#[derive(Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
enum Mode {
    Idle = 0,
    Primary = 2,
    Cleanup = 3,
}

pub(super) enum Tick {
    Continue,
    Stop,
}

pub(crate) enum Quota {
    Available,
    Exhausted,
}

#[repr(transparent)]
struct Counter(cell::Cell<u64>);

impl Meter {
    pub(super) const fn new() -> Self {
        Self {
            primary: Counter::new(),
            mode: cell::Cell::new(Mode::Idle),
            permission: cell::Cell::new(Permission::Denied),
        }
    }

    pub(super) fn reset(&self) {
        self.mode.set(Mode::Idle);
        self.permission.set(Permission::Denied);
    }

    pub(super) fn begin_call(&self, primary: limits::Progress) -> Result<(), crate::Error> {
        self.begin(Mode::Primary, primary)
    }

    pub(super) fn cleanup(&self, quota: limits::Progress) -> Result<(), crate::Error> {
        match self.mode.get() {
            Mode::Cleanup => Ok(()),
            Mode::Idle => self.begin(Mode::Cleanup, quota),
            Mode::Primary => Err(crate::Error::ReentrantQuery),
        }
    }

    pub(super) fn tick(&self) -> Tick {
        match self.mode.get() {
            Mode::Idle => Tick::Continue,
            Mode::Primary | Mode::Cleanup => self.primary.tick(),
        }
    }

    pub(super) fn call_quota(&self) -> Quota {
        self.primary.quota()
    }

    pub(super) fn finish(&self) {
        self.mode.set(Mode::Idle);
    }

    pub(super) fn stop(&self) {
        if matches!(self.mode.get(), Mode::Cleanup) {
            self.mode.set(Mode::Idle);
        }
    }

    pub(crate) fn run<T>(
        &self,
        op: impl FnOnce() -> Result<T, crate::Error>,
    ) -> Result<T, crate::Error> {
        match self.permission.replace(Permission::Granted) {
            Permission::Denied => {}
            Permission::Granted => return Err(crate::Error::ReentrantQuery),
        }
        let result = op();
        self.permission.set(Permission::Denied);
        result
    }

    pub(super) fn permission(&self) -> Permission {
        self.permission.get()
    }

    fn begin(&self, mode: Mode, primary: limits::Progress) -> Result<(), crate::Error> {
        if self.mode.get() != Mode::Idle {
            return Err(crate::Error::ReentrantQuery);
        }
        self.primary.start(primary);
        self.mode.set(mode);
        Ok(())
    }
}

impl Counter {
    const fn new() -> Self {
        Self(cell::Cell::new(0))
    }

    fn start(&self, quota: limits::Progress) {
        self.0.set(quota.get());
    }

    fn tick(&self) -> Tick {
        let left = self.0.get();
        if left == 0 {
            return Tick::Stop;
        }
        let left = left - 1;
        self.0.set(left);
        match left {
            0 => Tick::Stop,
            _ => Tick::Continue,
        }
    }

    fn quota(&self) -> Quota {
        match self.0.get() {
            0 => Quota::Exhausted,
            _ => Quota::Available,
        }
    }
}

const _: () = assert!(mem::size_of::<Meter>() <= 3 * mem::size_of::<u64>());