use chrono::{DateTime, Utc};
use serde::de::{self, Deserializer};
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EventKind {
Initial,
TransitionStart,
BusyStart,
BusyEnd,
ValueSample,
Settled,
Manual,
}
impl EventKind {
pub const ALL: [EventKind; 7] = [
EventKind::Initial,
EventKind::TransitionStart,
EventKind::BusyStart,
EventKind::BusyEnd,
EventKind::ValueSample,
EventKind::Settled,
EventKind::Manual,
];
pub fn as_str(self) -> &'static str {
match self {
EventKind::Initial => "initial",
EventKind::TransitionStart => "transition_start",
EventKind::BusyStart => "busy_start",
EventKind::BusyEnd => "busy_end",
EventKind::ValueSample => "value_sample",
EventKind::Settled => "settled",
EventKind::Manual => "manual",
}
}
#[inline]
fn bit(self) -> u8 {
match self {
EventKind::Initial => 1 << 0,
EventKind::TransitionStart => 1 << 1,
EventKind::BusyStart => 1 << 2,
EventKind::BusyEnd => 1 << 3,
EventKind::ValueSample => 1 << 4,
EventKind::Settled => 1 << 5,
EventKind::Manual => 1 << 6,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SaveMask(u8);
impl SaveMask {
pub const NONE: SaveMask = SaveMask(0);
pub fn from_kinds(kinds: &[EventKind]) -> Self {
let mut bits = 0u8;
for k in kinds {
bits |= k.bit();
}
SaveMask(bits)
}
#[inline]
pub fn contains(self, kind: EventKind) -> bool {
self.0 & kind.bit() != 0
}
pub fn with(mut self, kind: EventKind) -> Self {
self.0 |= kind.bit();
self
}
pub fn kinds(self) -> Vec<EventKind> {
EventKind::ALL
.iter()
.copied()
.filter(|k| self.contains(*k))
.collect()
}
}
impl Default for SaveMask {
fn default() -> Self {
SaveMask::from_kinds(&[
EventKind::Initial,
EventKind::Settled,
EventKind::BusyEnd,
EventKind::Manual,
])
}
}
impl Serialize for SaveMask {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.kinds().serialize(s)
}
}
impl<'de> Deserialize<'de> for SaveMask {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let kinds = Vec::<EventKind>::deserialize(d).map_err(de::Error::custom)?;
Ok(SaveMask::from_kinds(&kinds))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ImageFormat {
Png,
Jpeg,
Webp,
}
impl ImageFormat {
pub fn ext(self) -> &'static str {
match self {
ImageFormat::Png => "png",
ImageFormat::Jpeg => "jpg",
ImageFormat::Webp => "webp",
}
}
}
#[derive(Debug, Clone)]
pub struct EncodedImage {
pub bytes: Vec<u8>,
pub format: ImageFormat,
pub width: u32,
pub height: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WindowMeta {
pub title: String,
pub exe: String,
pub class: String,
pub hwnd: isize,
pub rect: [i32; 4],
pub dpi: u32,
pub foreground: bool,
}
pub type BBox = [i32; 4];
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChangeMeta {
pub changed_tiles: u32,
pub tile_grid: [u16; 2],
pub area_ratio: f32,
pub bboxes: Vec<BBox>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dhash: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hamming_to_prev_emit: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegionMeta {
pub label: String,
pub active: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BusyMeta {
pub active: bool,
pub regions: Vec<RegionMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimingMeta {
#[serde(skip_serializing_if = "Option::is_none")]
pub since_prev_emit_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub active_for_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quiescent_for_ms: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CaptureMeta {
pub session_id: String,
pub seq: u64,
pub id: String,
pub kind: EventKind,
pub wall_time: DateTime<Utc>,
pub elapsed_ms: u64,
pub image: Option<String>,
pub window: WindowMeta,
pub change: ChangeMeta,
pub busy: BusyMeta,
pub timing: TimingMeta,
pub coalesced_frames: u32,
pub note: String,
}
#[derive(Debug, Clone)]
pub struct CaptureEvent {
pub meta: CaptureMeta,
pub image: Option<EncodedImage>,
}
impl CaptureEvent {
pub fn kind(&self) -> EventKind {
self.meta.kind
}
}