nros_log/sinks.rs
1//! Phase 88.4 — `PlatformSink` + helpers.
2//!
3//! The portable facade ships exactly ONE sink: [`PlatformSink`].
4//! It forwards every record to `nros_platform_log_write` (declared
5//! in `nros-platform-cffi` / extended in Phase 88.3). Per-platform
6//! `nros-platform-<rtos>` crates own the actual delivery.
7//!
8//! Apps wanting fan-out (e.g. `Platform + /rosout` or stdout in a
9//! test harness) compose their own `&'static [&dyn LogSink]` and
10//! pass it to [`crate::init`].
11
12use crate::{LogSink, Record};
13
14unsafe extern "C" {
15 /// Per-platform log delivery (Phase 88). Declared in
16 /// `<nros/platform.h>`; implementor lives in each
17 /// `nros-platform-<rtos>` crate.
18 pub fn nros_platform_log_write(
19 severity: u8,
20 name_ptr: *const u8,
21 name_len: usize,
22 msg_ptr: *const u8,
23 msg_len: usize,
24 );
25
26 /// Per-platform log flush. Default no-op on platforms that
27 /// don't buffer.
28 pub fn nros_platform_log_flush();
29}
30
31/// The default sink: forwards to `nros_platform_log_write`.
32///
33/// Zero-sized. Threading + ISR safety inherit from the linked
34/// `nros-platform-<rtos>` impl — see the table in
35/// `docs/roadmap/archived/phase-88-nros-log.md`.
36pub struct PlatformSink;
37
38impl LogSink for PlatformSink {
39 fn log(&self, record: &Record<'_>) {
40 let name = record.logger_name.as_bytes();
41 let msg = record.message.as_bytes();
42 // SAFETY: pointers come from `&str` / `&'a [u8]` references
43 // that outlive the call; lengths match.
44 unsafe {
45 nros_platform_log_write(
46 record.severity.as_u8(),
47 name.as_ptr(),
48 name.len(),
49 msg.as_ptr(),
50 msg.len(),
51 );
52 }
53 }
54
55 fn flush(&self) {
56 // SAFETY: no args, no preconditions.
57 unsafe { nros_platform_log_flush() };
58 }
59}
60
61static PLATFORM_SINK: PlatformSink = PlatformSink;
62
63/// The default sink list: just `&PLATFORM_SINK`.
64///
65/// Pass to [`crate::init`] for the common case:
66///
67/// ```ignore
68/// nros_log::init(nros_log::sinks::default());
69/// ```
70#[must_use]
71pub fn default() -> &'static [&'static dyn LogSink] {
72 static SINKS: &[&dyn LogSink] = &[&PLATFORM_SINK];
73 SINKS
74}