| 1 | mod integers; |
| 2 | mod traits; |
| 3 | |
| 4 | use core::fmt::Write as _; |
| 5 | |
| 6 | use crate::{Format, Formatter, Str}; |
| 7 | |
| 8 | pub use self::integers::*; |
| 9 | pub use bitflags::bitflags; |
| 10 | |
| 11 | pub trait UnsignedInt {} |
| 12 | impl UnsignedInt for u8 {} |
| 13 | impl UnsignedInt for u16 {} |
| 14 | impl UnsignedInt for u32 {} |
| 15 | impl UnsignedInt for u64 {} |
| 16 | impl UnsignedInt for u128 {} |
| 17 | |
| 18 | #[cfg (feature = "unstable-test" )] |
| 19 | thread_local! { |
| 20 | static I: core::sync::atomic::AtomicU16 = const { core::sync::atomic::AtomicU16::new(0) }; |
| 21 | static BYTES: core::cell::RefCell<Vec<u8>> = const { core::cell::RefCell::new(Vec::new()) }; |
| 22 | } |
| 23 | |
| 24 | /// For testing purposes |
| 25 | #[cfg (feature = "unstable-test" )] |
| 26 | pub fn fetch_string_index() -> u16 { |
| 27 | I.with(|i| i.load(core::sync::atomic::Ordering::Relaxed)) |
| 28 | } |
| 29 | |
| 30 | /// For testing purposes |
| 31 | #[cfg (feature = "unstable-test" )] |
| 32 | pub fn fetch_add_string_index() -> u16 { |
| 33 | I.with(|i| i.fetch_add(1, core::sync::atomic::Ordering::Relaxed)) |
| 34 | } |
| 35 | |
| 36 | /// Get and clear the logged bytes |
| 37 | #[cfg (feature = "unstable-test" )] |
| 38 | pub fn fetch_bytes() -> Vec<u8> { |
| 39 | BYTES.with(|b| core::mem::take(&mut *b.borrow_mut())) |
| 40 | } |
| 41 | |
| 42 | /// Only to be used by the defmt macros |
| 43 | /// Safety: must be paired with a later call to release() |
| 44 | #[cfg (feature = "unstable-test" )] |
| 45 | pub unsafe fn acquire() {} |
| 46 | |
| 47 | /// Only to be used by the defmt macros |
| 48 | /// Safety: must be paired with a later call to release() |
| 49 | #[cfg (not(feature = "unstable-test" ))] |
| 50 | #[inline (always)] |
| 51 | pub unsafe fn acquire() { |
| 52 | unsafeextern "Rust" { |
| 53 | unsafefn _defmt_acquire(); |
| 54 | } |
| 55 | _defmt_acquire() |
| 56 | } |
| 57 | |
| 58 | /// Only to be used by the defmt macros |
| 59 | /// Safety: must follow an earlier call to acquire() |
| 60 | #[cfg (feature = "unstable-test" )] |
| 61 | pub unsafe fn release() {} |
| 62 | |
| 63 | /// Only to be used by the defmt macros |
| 64 | /// Safety: must follow an earlier call to acquire() |
| 65 | #[cfg (not(feature = "unstable-test" ))] |
| 66 | #[inline (always)] |
| 67 | pub unsafe fn release() { |
| 68 | unsafeextern "Rust" { |
| 69 | unsafefn _defmt_release(); |
| 70 | } |
| 71 | _defmt_release() |
| 72 | } |
| 73 | |
| 74 | #[cfg (feature = "unstable-test" )] |
| 75 | pub fn write(bytes: &[u8]) { |
| 76 | BYTES.with(|b| b.borrow_mut().extend(bytes)) |
| 77 | } |
| 78 | |
| 79 | #[cfg (not(feature = "unstable-test" ))] |
| 80 | #[inline (always)] |
| 81 | pub fn write(bytes: &[u8]) { |
| 82 | unsafeextern "Rust" { |
| 83 | unsafefn _defmt_write(bytes: &[u8]); |
| 84 | } |
| 85 | unsafe { _defmt_write(bytes) } |
| 86 | } |
| 87 | |
| 88 | /// For testing purposes |
| 89 | #[cfg (feature = "unstable-test" )] |
| 90 | pub fn timestamp(_fmt: crate::Formatter<'_>) {} |
| 91 | |
| 92 | #[cfg (not(feature = "unstable-test" ))] |
| 93 | #[inline (always)] |
| 94 | pub fn timestamp(fmt: crate::Formatter<'_>) { |
| 95 | unsafeextern "Rust" { |
| 96 | unsafefn _defmt_timestamp(_: crate::Formatter<'_>); |
| 97 | } |
| 98 | unsafe { _defmt_timestamp(fmt) } |
| 99 | } |
| 100 | |
| 101 | /// Returns the interned string at `address`. |
| 102 | pub fn make_istr(address: u16) -> Str { |
| 103 | Str { address } |
| 104 | } |
| 105 | |
| 106 | /// Create a Formatter. |
| 107 | pub fn make_formatter<'a>() -> Formatter<'a> { |
| 108 | Formatter { |
| 109 | _phantom: core::marker::PhantomData, |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | pub fn truncate<T>(x: impl traits::Truncate<T>) -> T { |
| 114 | x.truncate() |
| 115 | } |
| 116 | |
| 117 | pub fn into_result<T: traits::IntoResult>(x: T) -> Result<T::Ok, T::Error> { |
| 118 | x.into_result() |
| 119 | } |
| 120 | |
| 121 | /// For testing purposes |
| 122 | #[cfg (feature = "unstable-test" )] |
| 123 | pub fn panic() -> ! { |
| 124 | panic!() |
| 125 | } |
| 126 | |
| 127 | #[cfg (not(feature = "unstable-test" ))] |
| 128 | #[inline (always)] |
| 129 | pub fn panic() -> ! { |
| 130 | unsafeextern "Rust" { |
| 131 | unsafefn _defmt_panic() -> !; |
| 132 | } |
| 133 | unsafe { _defmt_panic() } |
| 134 | } |
| 135 | |
| 136 | /// Implementation detail |
| 137 | pub fn fmt<T: Format + ?Sized>(f: &T) { |
| 138 | istr(&T::_format_tag()); |
| 139 | f._format_data(); |
| 140 | } |
| 141 | |
| 142 | /// Implementation detail |
| 143 | pub fn fmt_slice<T: Format>(values: &[T]) { |
| 144 | usize(&values.len()); |
| 145 | istr(&T::_format_tag()); |
| 146 | for value: &T in values { |
| 147 | value._format_data(); |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | /// Implementation detail |
| 152 | pub fn f32(b: &f32) { |
| 153 | write(&f32::to_bits(*b).to_le_bytes()) |
| 154 | } |
| 155 | |
| 156 | /// Implementation detail |
| 157 | pub fn f64(b: &f64) { |
| 158 | write(&f64::to_bits(*b).to_le_bytes()) |
| 159 | } |
| 160 | |
| 161 | /// Implementation detail |
| 162 | pub fn char(b: &char) { |
| 163 | write(&(*b as u32).to_le_bytes()) |
| 164 | } |
| 165 | |
| 166 | pub fn str(s: &str) { |
| 167 | usize(&s.len()); |
| 168 | write(s.as_bytes()); |
| 169 | } |
| 170 | |
| 171 | pub fn slice(s: &[u8]) { |
| 172 | usize(&s.len()); |
| 173 | write(bytes:s); |
| 174 | } |
| 175 | |
| 176 | // NOTE: This is passed `&[u8; N]` – it's just coerced to a slice. |
| 177 | pub fn u8_array(a: &[u8]) { |
| 178 | write(bytes:a); |
| 179 | } |
| 180 | |
| 181 | // NOTE: This is passed `&[u8; N]` – it's just coerced to a slice. |
| 182 | pub fn fmt_array<T: Format>(a: &[T]) { |
| 183 | istr(&T::_format_tag()); |
| 184 | for value: &T in a { |
| 185 | value._format_data(); |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | /// Implementation detail |
| 190 | pub fn istr(s: &Str) { |
| 191 | write(&s.address.to_le_bytes()) |
| 192 | } |
| 193 | |
| 194 | /// Implementation detail |
| 195 | pub fn bool(b: &bool) { |
| 196 | u8(&(*b as u8)); |
| 197 | } |
| 198 | |
| 199 | /// Implementation detail |
| 200 | pub fn debug(val: &dyn core::fmt::Debug) { |
| 201 | core::write!(FmtWrite, " {val:?}" ).ok(); |
| 202 | write(&[0xff]); |
| 203 | } |
| 204 | |
| 205 | /// Implementation detail |
| 206 | pub fn display(val: &dyn core::fmt::Display) { |
| 207 | core::write!(FmtWrite, " {val}" ).ok(); |
| 208 | write(&[0xff]); |
| 209 | } |
| 210 | |
| 211 | #[inline (never)] |
| 212 | pub unsafe fn acquire_and_header(s: &Str) { |
| 213 | acquire(); |
| 214 | istr(s); |
| 215 | timestamp(fmt:make_formatter()); |
| 216 | } |
| 217 | |
| 218 | #[inline (never)] |
| 219 | pub fn acquire_header_and_release(s: &Str) { |
| 220 | // safety: will be released a few lines further down |
| 221 | unsafe { acquire() }; |
| 222 | istr(s); |
| 223 | timestamp(fmt:make_formatter()); |
| 224 | // safety: acquire() was called a few lines above |
| 225 | unsafe { release() }; |
| 226 | } |
| 227 | |
| 228 | struct FmtWrite; |
| 229 | |
| 230 | impl core::fmt::Write for FmtWrite { |
| 231 | fn write_str(&mut self, s: &str) -> core::fmt::Result { |
| 232 | write(s.as_bytes()); |
| 233 | Ok(()) |
| 234 | } |
| 235 | } |
| 236 | |