Skip to content

Commit 151aefc

Browse files
authored
Merge pull request #85 from rust-mobile/refactor-structure
Split things into different files, to optimize future work
2 parents b4f7783 + 1b5dd78 commit 151aefc

File tree

7 files changed

+591
-565
lines changed

7 files changed

+591
-565
lines changed

rustfmt.toml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
style_edition = "2024"

src/arrays.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use crate::LOGGING_TAG_MAX_LEN;
2+
use std::ffi::CStr;
3+
use std::mem::MaybeUninit;
4+
5+
// FIXME: When `maybe_uninit_uninit_array` is stabilized, use it instead of this helper
6+
pub fn uninit_array<const N: usize, T>() -> [MaybeUninit<T>; N] {
7+
// SAFETY: Array contains MaybeUninit, which is fine to be uninit
8+
unsafe { MaybeUninit::uninit().assume_init() }
9+
}
10+
11+
// FIXME: Remove when maybe_uninit_slice is stabilized to provide MaybeUninit::slice_assume_init_ref()
12+
pub unsafe fn slice_assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T] {
13+
&*(slice as *const [MaybeUninit<T>] as *const [T])
14+
}
15+
16+
/// Fills up `storage` with `tag` and a necessary NUL terminator, optionally ellipsizing the input
17+
/// `tag` if it's too large.
18+
///
19+
/// Returns a [`CStr`] containing the initialized portion of `storage`, including its NUL
20+
/// terminator.
21+
pub fn fill_tag_bytes<'a>(
22+
storage: &'a mut [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1],
23+
tag: &[u8],
24+
) -> &'a CStr {
25+
// FIXME: Simplify when maybe_uninit_fill with MaybeUninit::fill_from() is stabilized
26+
let initialized = if tag.len() > LOGGING_TAG_MAX_LEN {
27+
for (input, output) in tag
28+
.iter()
29+
// Elipsize the last two characters (TODO: use special … character)?
30+
.take(LOGGING_TAG_MAX_LEN - 2)
31+
.chain(b"..\0")
32+
.zip(storage.iter_mut())
33+
{
34+
output.write(*input);
35+
}
36+
storage.as_slice()
37+
} else {
38+
for (input, output) in tag.iter().chain(b"\0").zip(storage.iter_mut()) {
39+
output.write(*input);
40+
}
41+
&storage[..tag.len() + 1]
42+
};
43+
44+
// SAFETY: The above code ensures that `initialized` only refers to a portion of the `array`
45+
// slice that was initialized, thus it is safe to cast those `MaybeUninit<u8>`s to `u8`:
46+
let initialized = unsafe { slice_assume_init_ref(initialized) };
47+
CStr::from_bytes_with_nul(initialized).expect("Unreachable: we wrote a nul terminator")
48+
}

src/config.rs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use crate::{FormatFn, LogId};
2+
use log::{Level, LevelFilter, Record};
3+
use std::ffi::CString;
4+
use std::fmt;
5+
6+
/// Filter for android logger.
7+
#[derive(Default)]
8+
pub struct Config {
9+
pub(crate) log_level: Option<LevelFilter>,
10+
pub(crate) buf_id: Option<LogId>,
11+
filter: Option<env_filter::Filter>,
12+
pub(crate) tag: Option<CString>,
13+
pub(crate) custom_format: Option<FormatFn>,
14+
}
15+
16+
impl fmt::Debug for Config {
17+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18+
f.debug_struct("Config")
19+
.field("log_level", &self.log_level)
20+
.field("buf_id", &self.buf_id)
21+
.field("filter", &self.filter)
22+
.field("tag", &self.tag)
23+
.field("custom_format", match &self.custom_format {
24+
Some(_) => &"Some(_)",
25+
None => &"None",
26+
})
27+
.finish()
28+
}
29+
}
30+
31+
impl Config {
32+
/// Changes the maximum log level.
33+
///
34+
/// Note, that `Trace` is the maximum level, because it provides the
35+
/// maximum amount of detail in the emitted logs.
36+
///
37+
/// If `Off` level is provided, then nothing is logged at all.
38+
///
39+
/// [`log::max_level()`] is considered as the default level.
40+
pub fn with_max_level(mut self, level: LevelFilter) -> Self {
41+
self.log_level = Some(level);
42+
self
43+
}
44+
45+
/// Changes the Android logging system buffer to be used.
46+
///
47+
/// By default, logs are sent to the [`Main`] log. Other logging buffers may
48+
/// only be accessible to certain processes.
49+
///
50+
/// [`Main`]: LogId::Main
51+
pub fn with_log_buffer(mut self, buf_id: LogId) -> Self {
52+
self.buf_id = Some(buf_id);
53+
self
54+
}
55+
56+
pub(crate) fn filter_matches(&self, record: &Record) -> bool {
57+
if let Some(ref filter) = self.filter {
58+
filter.matches(record)
59+
} else {
60+
true
61+
}
62+
}
63+
64+
pub(crate) fn is_loggable(&self, level: Level) -> bool {
65+
// todo: consider __android_log_is_loggable.
66+
level <= self.log_level.unwrap_or_else(log::max_level)
67+
}
68+
69+
pub fn with_filter(mut self, filter: env_filter::Filter) -> Self {
70+
self.filter = Some(filter);
71+
self
72+
}
73+
74+
pub fn with_tag<S: Into<Vec<u8>>>(mut self, tag: S) -> Self {
75+
self.tag = Some(CString::new(tag).expect("Can't convert tag to CString"));
76+
self
77+
}
78+
79+
/// Sets the format function for formatting the log output.
80+
/// ```
81+
/// # use android_logger::Config;
82+
/// android_logger::init_once(
83+
/// Config::default()
84+
/// .with_max_level(log::LevelFilter::Trace)
85+
/// .format(|f, record| write!(f, "my_app: {}", record.args()))
86+
/// )
87+
/// ```
88+
pub fn format<F>(mut self, format: F) -> Self
89+
where
90+
F: Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send + 'static,
91+
{
92+
self.custom_format = Some(Box::new(format));
93+
self
94+
}
95+
}

src/id.rs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/// Possible identifiers of a specific buffer of Android logging system for
2+
/// logging a message.
3+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4+
pub enum LogId {
5+
/// Main log buffer.
6+
///
7+
/// This is the only log buffer available to apps.
8+
Main,
9+
10+
/// Radio log buffer.
11+
Radio,
12+
13+
/// Event log buffer.
14+
Events,
15+
16+
/// System log buffer.
17+
System,
18+
19+
/// Crash log buffer.
20+
Crash,
21+
22+
/// Kernel log buffer.
23+
Kernel,
24+
25+
/// Security log buffer.
26+
Security,
27+
28+
/// Statistics log buffer.
29+
Stats,
30+
}
31+
32+
#[cfg(target_os = "android")]
33+
impl LogId {
34+
pub(crate) const fn to_native(log_id: Option<Self>) -> Option<log_ffi::log_id_t> {
35+
match log_id {
36+
Some(Self::Main) => Some(log_ffi::log_id_t::MAIN),
37+
Some(Self::Radio) => Some(log_ffi::log_id_t::RADIO),
38+
Some(Self::Events) => Some(log_ffi::log_id_t::EVENTS),
39+
Some(Self::System) => Some(log_ffi::log_id_t::SYSTEM),
40+
Some(Self::Crash) => Some(log_ffi::log_id_t::CRASH),
41+
Some(Self::Kernel) => Some(log_ffi::log_id_t::KERNEL),
42+
Some(Self::Security) => Some(log_ffi::log_id_t::SECURITY),
43+
Some(Self::Stats) => Some(log_ffi::log_id_t::STATS),
44+
None => None,
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)