use epics_base_rs::server::access_security::AccessLevel;
use crate::protocol::{ECA_NORDACCESS, ECA_NOWTACCESS};
#[derive(Debug, Clone, Copy)]
pub struct CaAccessChecked {
level: AccessLevel,
_seal: AccessSeal,
}
#[derive(Debug, Clone, Copy)]
struct AccessSeal;
#[derive(Debug, Clone, Copy)]
pub struct ReadGranted {
_seal: AccessSeal,
}
#[derive(Debug, Clone, Copy)]
pub struct WriteGranted {
_seal: AccessSeal,
}
#[derive(Debug, Clone, Copy)]
pub enum AccessDenied {
NoRead,
NoWrite,
}
impl AccessDenied {
pub fn eca_code(&self) -> u32 {
match self {
AccessDenied::NoRead => ECA_NORDACCESS,
AccessDenied::NoWrite => ECA_NOWTACCESS,
}
}
}
impl CaAccessChecked {
pub(crate) fn from_level(level: AccessLevel) -> Self {
Self {
level,
_seal: AccessSeal,
}
}
pub(crate) fn denied() -> Self {
Self::from_level(AccessLevel::NoAccess)
}
pub fn require_read(&self) -> Result<ReadGranted, AccessDenied> {
if matches!(self.level, AccessLevel::NoAccess) {
Err(AccessDenied::NoRead)
} else {
Ok(ReadGranted { _seal: AccessSeal })
}
}
pub fn require_write(&self) -> Result<WriteGranted, AccessDenied> {
if matches!(self.level, AccessLevel::ReadWrite) {
Ok(WriteGranted { _seal: AccessSeal })
} else {
Err(AccessDenied::NoWrite)
}
}
pub fn level(&self) -> AccessLevel {
self.level
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_access_denies_read_and_write() {
let c = CaAccessChecked::from_level(AccessLevel::NoAccess);
assert!(matches!(c.require_read(), Err(AccessDenied::NoRead)));
assert!(matches!(c.require_write(), Err(AccessDenied::NoWrite)));
}
#[test]
fn read_grants_read_denies_write() {
let c = CaAccessChecked::from_level(AccessLevel::Read);
assert!(c.require_read().is_ok());
assert!(matches!(c.require_write(), Err(AccessDenied::NoWrite)));
}
#[test]
fn read_write_grants_both() {
let c = CaAccessChecked::from_level(AccessLevel::ReadWrite);
assert!(c.require_read().is_ok());
assert!(c.require_write().is_ok());
}
#[test]
fn denied_helper_returns_no_access_token() {
let c = CaAccessChecked::denied();
assert!(matches!(c.require_read(), Err(AccessDenied::NoRead)));
assert!(matches!(c.require_write(), Err(AccessDenied::NoWrite)));
}
#[test]
fn eca_codes_match_wire_constants() {
assert_eq!(AccessDenied::NoRead.eca_code(), ECA_NORDACCESS);
assert_eq!(AccessDenied::NoWrite.eca_code(), ECA_NOWTACCESS);
}
}