aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs95
1 files changed, 57 insertions, 38 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 183559f..59f942b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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])
+ }
}