autd3-rs-core 0.9.0

Core types and link abstraction shared across the AUTD3 phased-array sdk crates.
Documentation
use std::io::{IsTerminal, Stderr, Stdout, Write};

use tracing_appender::non_blocking::WorkerGuard;

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum LogWriter {
    #[default]
    Stdout,
    Stderr,
}

#[derive(Clone, Copy, Debug)]
pub struct TracingOption {
    pub default_filter: &'static str,
    pub writer: LogWriter,
}

impl Default for TracingOption {
    fn default() -> Self {
        Self {
            default_filter: "info",
            writer: LogWriter::default(),
        }
    }
}

#[must_use]
pub struct TracingGuard(#[expect(dead_code)] WorkerGuard);

enum Sink {
    Stdout(Stdout),
    Stderr(Stderr),
}

impl Sink {
    fn is_terminal(&self) -> bool {
        match self {
            Self::Stdout(w) => w.is_terminal(),
            Self::Stderr(w) => w.is_terminal(),
        }
    }
}

impl Write for Sink {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::Stdout(w) => w.write(buf),
            Self::Stderr(w) => w.write(buf),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::Stdout(w) => w.flush(),
            Self::Stderr(w) => w.flush(),
        }
    }
}

pub fn init_tracing(option: TracingOption) -> TracingGuard {
    let filter = tracing_subscriber::EnvFilter::try_from_default_env()
        .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(option.default_filter));
    let sink = match option.writer {
        LogWriter::Stdout => Sink::Stdout(std::io::stdout()),
        LogWriter::Stderr => Sink::Stderr(std::io::stderr()),
    };
    let no_color = std::env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty());
    let ansi = sink.is_terminal() && !no_color;
    let (writer, guard) = tracing_appender::non_blocking(sink);
    let builder = tracing_subscriber::fmt()
        .with_env_filter(filter)
        .with_writer(writer)
        .with_ansi(ansi);
    if std::env::var_os("JOURNAL_STREAM").is_some() {
        builder.without_time().init();
    } else {
        builder.init();
    }
    TracingGuard(guard)
}