use core::{fmt, ptr};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time::Duration};
use crate::decode::LogRecord;
use crate::encode::{CustomEncode, Decoder};
use crate::level::LogLevel;
use crate::sink::{Sink, SinkError};
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
}
unsafe impl CustomEncode for Color {
fn payload_size(&self) -> usize {
3
}
unsafe fn encode_payload(&self, dst: *mut u8) {
unsafe {
*dst = self.r;
*dst.add(1) = self.g;
*dst.add(2) = self.b;
}
}
fn decoder() -> Decoder {
|bytes, out: &mut dyn fmt::Write| {
write!(out, "rgb({}, {}, {})", bytes[0], bytes[1], bytes[2])
}
}
}
pub struct Point2D {
pub x: f32,
pub y: f32,
}
unsafe impl CustomEncode for Point2D {
fn payload_size(&self) -> usize {
8
}
unsafe fn encode_payload(&self, dst: *mut u8) {
let xb = self.x.to_ne_bytes();
let yb = self.y.to_ne_bytes();
unsafe {
ptr::copy_nonoverlapping(xb.as_ptr(), dst, 4);
ptr::copy_nonoverlapping(yb.as_ptr(), dst.add(4), 4);
}
}
fn decoder() -> Decoder {
|bytes, out: &mut dyn fmt::Write| {
let x = f32::from_ne_bytes(bytes[..4].try_into().unwrap());
let y = f32::from_ne_bytes(bytes[4..].try_into().unwrap());
write!(out, "({x}, {y})")
}
}
}
pub struct Marker;
unsafe impl CustomEncode for Marker {
fn payload_size(&self) -> usize {
0
}
unsafe fn encode_payload(&self, _dst: *mut u8) {}
fn decoder() -> Decoder {
|_bytes, out: &mut dyn fmt::Write| write!(out, "marker")
}
}
pub fn spin_until(pred: impl Fn() -> bool, timeout: Duration) -> bool {
let deadline = std::time::Instant::now() + timeout;
while std::time::Instant::now() < deadline {
if pred() {
return true;
}
thread::yield_now();
}
false
}
pub struct RecordingSink {
level: LogLevel,
count: AtomicUsize,
}
impl RecordingSink {
#[must_use]
pub const fn new(level: LogLevel) -> Self {
Self {
level,
count: AtomicUsize::new(0),
}
}
pub fn record_count(&self) -> usize {
self.count.load(Ordering::Acquire)
}
}
impl Sink for RecordingSink {
fn write_record(&self, _record: &LogRecord) -> Result<(), SinkError> {
self.count.fetch_add(1, Ordering::Release);
Ok(())
}
fn flush(&self) -> Result<(), SinkError> {
Ok(())
}
fn level(&self) -> LogLevel {
self.level
}
}