diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 95 |
1 files changed, 57 insertions, 38 deletions
@@ -72,15 +72,15 @@ extern crate log; extern crate env_logger; +use log::{Level, Log, Metadata, Record}; #[cfg(target_os = "android")] use log_ffi::LogPriority; -use log::{Level, Log, Metadata, Record}; use std::ffi::{CStr, CString}; -use std::mem; use std::fmt; +use std::mem::{self, MaybeUninit}; use std::ptr; -pub use env_logger::filter::{Filter, Builder as FilterBuilder}; +pub use env_logger::filter::{Builder as FilterBuilder, Filter}; pub use env_logger::fmt::Formatter; pub(crate) type FormatFn = Box<dyn Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send>; @@ -137,7 +137,6 @@ impl AndroidLogger { } } - static ANDROID_LOGGER: OnceCell<AndroidLogger> = OnceCell::new(); const LOGGING_TAG_MAX_LEN: usize = 23; @@ -158,22 +157,23 @@ impl Log for AndroidLogger { } fn log(&self, record: &Record) { - let config = self.config - .get_or_init(Config::default); + let config = self.config.get_or_init(Config::default); if !config.filter_matches(record) { return; } // tag must not exceed LOGGING_TAG_MAX_LEN - #[allow(deprecated)] // created an issue #35 for this - let mut tag_bytes: [u8; LOGGING_TAG_MAX_LEN + 1] = unsafe { mem::uninitialized() }; + let mut tag_bytes: [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1] = uninit_array(); let module_path = record.module_path().unwrap_or_default().to_owned(); // If no tag was specified, use module name let custom_tag = &config.tag; - let tag = custom_tag.as_ref().map(|s| s.as_bytes()).unwrap_or_else(|| module_path.as_bytes()); + let tag = custom_tag + .as_ref() + .map(|s| s.as_bytes()) + .unwrap_or_else(|| module_path.as_bytes()); // truncate the tag here to fit into LOGGING_TAG_MAX_LEN self.fill_tag_bytes(&mut tag_bytes, tag); @@ -203,21 +203,19 @@ impl Log for AndroidLogger { } impl AndroidLogger { - fn fill_tag_bytes(&self, array: &mut [u8], tag: &[u8]) { + fn fill_tag_bytes(&self, array: &mut [MaybeUninit<u8>], tag: &[u8]) { if tag.len() > LOGGING_TAG_MAX_LEN { - for (input, output) in tag.iter() + for (input, output) in tag + .iter() .take(LOGGING_TAG_MAX_LEN - 2) .chain(b"..\0".iter()) .zip(array.iter_mut()) { - *output = *input; + output.write(*input); } } else { - for (input, output) in tag.iter() - .chain(b"\0".iter()) - .zip(array.iter_mut()) - { - *output = *input; + for (input, output) in tag.iter().chain(b"\0".iter()).zip(array.iter_mut()) { + output.write(*input); } } } @@ -288,15 +286,17 @@ impl Config { } } -struct PlatformLogWriter<'a> { - #[cfg(target_os = "android")] priority: LogPriority, - #[cfg(not(target_os = "android"))] priority: Level, +pub struct PlatformLogWriter<'a> { + #[cfg(target_os = "android")] + priority: LogPriority, + #[cfg(not(target_os = "android"))] + priority: Level, #[cfg(target_os = "android")] log_id: log_ffi::log_id_t, #[cfg(not(target_os = "android"))] log_id: Option<LogId>, len: usize, last_newline_index: usize, tag: &'a CStr, - buffer: [u8; LOGGING_MSG_MAX_LEN + 1], + buffer: [MaybeUninit<u8>; LOGGING_MSG_MAX_LEN + 1], } impl<'a> PlatformLogWriter<'a> { @@ -315,7 +315,7 @@ impl<'a> PlatformLogWriter<'a> { len: 0, last_newline_index: 0, tag, - buffer: unsafe { mem::uninitialized() }, + buffer: uninit_array(), } } @@ -328,7 +328,7 @@ impl<'a> PlatformLogWriter<'a> { len: 0, last_newline_index: 0, tag, - buffer: unsafe { mem::uninitialized() }, + buffer: uninit_array(), } } @@ -360,7 +360,7 @@ impl<'a> PlatformLogWriter<'a> { } /// Flush everything remaining to android logger. - fn flush(&mut self) { + pub fn flush(&mut self) { let total_len = self.len; if total_len == 0 { @@ -374,21 +374,22 @@ impl<'a> PlatformLogWriter<'a> { /// Output buffer up until the \0 which will be placed at `len` position. fn output_specified_len(&mut self, len: usize) { - let mut last_byte: u8 = b'\0'; + let mut last_byte = MaybeUninit::new(b'\0'); + mem::swap(&mut last_byte, unsafe { self.buffer.get_unchecked_mut(len) }); - let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) }; + let msg: &CStr = unsafe { CStr::from_ptr(self.buffer.as_ptr().cast()) }; android_log(self.log_id, self.priority, self.tag, msg); - *unsafe { self.buffer.get_unchecked_mut(len) } = last_byte; + unsafe { *self.buffer.get_unchecked_mut(len) = last_byte }; } /// Copy `len` bytes from `index` position to starting position. fn copy_bytes_to_start(&mut self, index: usize, len: usize) { - let src = unsafe { self.buffer.as_ptr().add(index) }; let dst = self.buffer.as_mut_ptr(); + let src = unsafe { self.buffer.as_ptr().add(index) }; unsafe { ptr::copy(src, dst, len) }; } } @@ -407,7 +408,7 @@ impl<'a> fmt::Write for PlatformLogWriter<'a> { .zip(incomming_bytes) .enumerate() .fold(None, |acc, (i, (output, input))| { - *output = *input; + output.write(*input); if *input == b'\n' { Some(i) } else { @@ -445,7 +446,9 @@ impl<'a> fmt::Write for PlatformLogWriter<'a> { /// This action does not require initialization. However, without initialization it /// will use the default filter, which allows all logs. pub fn log(record: &Record) { - ANDROID_LOGGER.get_or_init(AndroidLogger::default).log(record) + ANDROID_LOGGER + .get_or_init(AndroidLogger::default) + .log(record) } /// Initializes the global logger with an android logger. @@ -466,6 +469,12 @@ pub fn init_once(config: Config) { } } +// FIXME: When `maybe_uninit_uninit_array ` is stabilized, use it instead of this helper +fn uninit_array<const N: usize, T>() -> [MaybeUninit<T>; N] { + // SAFETY: Array contains MaybeUninit, which is fine to be uninit + unsafe { MaybeUninit::uninit().assume_init() } +} + #[cfg(test)] mod tests { use super::*; @@ -527,12 +536,12 @@ mod tests { let logger = AndroidLogger::new(Config::default()); let too_long_tag: [u8; LOGGING_TAG_MAX_LEN + 20] = [b'a'; LOGGING_TAG_MAX_LEN + 20]; - let mut result: [u8; LOGGING_TAG_MAX_LEN + 1] = Default::default(); + let mut result: [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1] = uninit_array(); logger.fill_tag_bytes(&mut result, &too_long_tag); let mut expected_result = [b'a'; LOGGING_TAG_MAX_LEN - 2].to_vec(); expected_result.extend("..\0".as_bytes()); - assert_eq!(result.to_vec(), expected_result); + assert_eq!(unsafe { assume_init_slice(&result) }, expected_result); } #[test] @@ -540,12 +549,12 @@ mod tests { let logger = AndroidLogger::new(Config::default()); let short_tag: [u8; 3] = [b'a'; 3]; - let mut result: [u8; LOGGING_TAG_MAX_LEN + 1] = Default::default(); + let mut result: [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1] = uninit_array(); logger.fill_tag_bytes(&mut result, &short_tag); let mut expected_result = short_tag.to_vec(); expected_result.push(0); - assert_eq!(result.to_vec()[..4], expected_result); + assert_eq!(unsafe { assume_init_slice(&result[..4]) }, expected_result); } #[test] @@ -573,7 +582,10 @@ mod tests { // Should have flushed up until the last newline. assert_eq!(writer.len, 3); assert_eq!(writer.last_newline_index, 0); - assert_eq!(&writer.buffer.to_vec()[..writer.len], "\n90".as_bytes()); + assert_eq!( + unsafe { assume_init_slice(&writer.buffer[..writer.len]) }, + "\n90".as_bytes() + ); writer.temporal_flush(); // Should have flushed all remaining bytes. @@ -616,7 +628,7 @@ mod tests { writer.output_specified_len(5); assert_eq!( - writer.buffer[..log_string.len()].to_vec(), + unsafe { assume_init_slice(&writer.buffer[..log_string.len()]) }, log_string.as_bytes() ); } @@ -630,7 +642,10 @@ mod tests { writer.copy_bytes_to_start(3, 2); - assert_eq!(writer.buffer[..10].to_vec(), "3423456789".as_bytes()); + assert_eq!( + unsafe { assume_init_slice(&writer.buffer[..10]) }, + "3423456789".as_bytes() + ); } #[test] @@ -645,7 +660,7 @@ mod tests { writer.copy_bytes_to_start(10, 0); assert_eq!( - writer.buffer[..test_string.len()].to_vec(), + unsafe { assume_init_slice(&writer.buffer[..test_string.len()]) }, test_string.as_bytes() ); } @@ -653,4 +668,8 @@ mod tests { fn get_tag_writer() -> PlatformLogWriter<'static> { PlatformLogWriter::new(None, Level::Warn, CStr::from_bytes_with_nul(b"tag\0").unwrap()) } + + unsafe fn assume_init_slice<T>(slice: &[MaybeUninit<T>]) -> &[T] { + &*(slice as *const [MaybeUninit<T>] as *const [T]) + } } |