use bitflags::bitflags;
use crate::res::{Res, ResSet};
#[cfg(feature = "derive")]
pub use fav_derive::Status;
pub trait Status {
fn status(&self) -> i32;
fn status_mut(&mut self) -> &mut i32;
fn status_flags(&self) -> StatusFlags {
StatusFlags::from_bits_retain(self.status())
}
fn check_status(&self, status: StatusFlags) -> bool {
self.status_flags().contains(status)
}
fn set_status(&mut self, status: StatusFlags) {
*self.status_mut() = status.bits();
}
fn on_status(&mut self, status: StatusFlags) {
self.set_status(self.status_flags() | status);
}
fn off_status(&mut self, status: StatusFlags) {
self.set_status(self.status_flags() - status);
}
}
bitflags! {
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub struct StatusFlags: i32 {
#[allow(missing_docs)]
const FETCHED = 0b00001;
#[allow(missing_docs)]
const TRACK = 0b00010;
#[allow(missing_docs)]
const SAVED = 0b00100;
#[allow(missing_docs)]
const FAV = 0b01000;
#[allow(missing_docs)]
const EXPIRED = 0b10000;
}
}
pub trait SetStatusExt<R>: ResSet<R> + Status + Sized
where
R: Res,
{
fn with_res_status_on(mut self, status: StatusFlags) -> Self {
self.iter_mut().for_each(|r| r.on_status(status));
self
}
fn with_res_status_set(mut self, status: StatusFlags) -> Self {
self.iter_mut().for_each(|r| r.set_status(status));
self
}
}
impl<S, R> SetStatusExt<R> for S
where
R: Res,
S: ResSet<R> + Status + Sized,
{
}
pub trait ResStatusExt: Res + Status + Sized {
fn with_status_on(mut self, status: StatusFlags) -> Self {
self.on_status(status);
self
}
fn with_status_set(mut self, status: StatusFlags) -> Self {
self.set_status(status);
self
}
}
impl<R> ResStatusExt for R where R: Res + Status + Sized {}
impl From<i32> for StatusFlags {
fn from(value: i32) -> Self {
StatusFlags::from_bits_retain(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate as fav_core;
#[derive(Status, Default)]
struct StatusTest {
status: i32,
}
#[test]
fn status_flags_test() {
let mut status = StatusFlags::empty();
status.insert(StatusFlags::FETCHED);
assert!(status.intersects(StatusFlags::FETCHED));
assert_eq!(status.bits(), 1);
status.insert(StatusFlags::TRACK);
assert_eq!(status.bits(), 3);
}
#[test]
fn status_test() {
let mut status = StatusTest::default();
status.on_status(StatusFlags::FETCHED);
assert!(status.check_status(StatusFlags::FETCHED));
status.off_status(StatusFlags::FETCHED);
assert!(!status.check_status(StatusFlags::FETCHED));
status.on_status(StatusFlags::FETCHED);
status.on_status(StatusFlags::SAVED);
assert!(status.check_status(StatusFlags::FETCHED));
assert!(status.check_status(StatusFlags::SAVED));
}
}