Skip to content

Commit 9679ef2

Browse files
bump soprintln
1 parent d55cdd1 commit 9679ef2

File tree

13 files changed

+55
-190
lines changed

13 files changed

+55
-190
lines changed

Justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ check:
44
cargo hack --each-feature --exclude-all-features clippy --manifest-path rubicon/Cargo.toml
55

66
test:
7-
cargo run --manifest-path test-crates/bin/Cargo.toml
7+
SOPRINTLN=1 cargo run --manifest-path test-crates/bin/Cargo.toml

rubicon/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,3 @@ paste = { version = "1.0.15", optional = true }
2020
default = []
2121
export-globals = ["dep:paste"]
2222
import-globals = ["dep:paste"]
23-
soprintln = []

rubicon/src/lib.rs

Lines changed: 20 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#[cfg(all(feature = "export-globals", feature = "import-globals"))]
2-
compile_error!("The features `export-globals` and `import-globals` cannot be used together");
2+
compile_error!("The features `export-globals` and `import-globals` are mutually exclusive, see https://github.com/bearcove/rubicon");
33

44
#[cfg(any(feature = "export-globals", feature = "import-globals"))]
55
pub use paste::paste;
@@ -48,17 +48,24 @@ impl<T> Deref for TrustedExternDouble<T> {
4848
/// Usage:
4949
///
5050
/// ```ignore
51-
/// use rubicon::process_local;
52-
///
53-
/// process_local! {
54-
/// static FOO: u32 = 42;
51+
/// rubicon::thread_local! {
52+
/// static FOO: AtomicU32 = AtomicU32::new(42);
5553
/// }
5654
/// ```
5755
///
5856
/// This will import `FOO` if the `import-globals` feature is enabled, and export it if the
5957
/// `export-globals` feature is enabled.
6058
///
61-
/// If neither feature is enabled, this will expand to the static declaration itself.
59+
/// If neither feature is enabled, this will be equivalent to `std::thread_local!`.
60+
///
61+
/// This macro supports multiple declarations:
62+
///
63+
/// ```ignore
64+
/// rubicon::thread_local! {
65+
/// static FOO: AtomicU32 = AtomicU32::new(42);
66+
/// static BAR: AtomicU32 = AtomicU32::new(43);
67+
/// }
68+
/// ```
6269
#[cfg(not(any(feature = "import-globals", feature = "export-globals")))]
6370
#[macro_export]
6471
macro_rules! thread_local {
@@ -148,6 +155,13 @@ macro_rules! thread_local_inner {
148155
///
149156
/// This macro supports multiple declarations, along with `static mut` declarations
150157
/// (which have a slightly different expansion).
158+
///
159+
/// ```ignore
160+
/// rubicon::thread_local! {
161+
/// static FOO: AtomicU32 = AtomicU32::new(42);
162+
/// static mut BAR: Dispatcher = Dispatcher::new();
163+
/// }
164+
/// ```
151165
#[cfg(all(not(feature = "import-globals"), not(feature = "export-globals")))]
152166
#[macro_export]
153167
macro_rules! process_local {
@@ -242,171 +256,3 @@ macro_rules! process_local_inner_mut {
242256
}
243257
};
244258
}
245-
246-
//==============================================================================
247-
// soprintln
248-
//==============================================================================
249-
250-
/// Note: there's one copy of this static per shared object on purpose — that's the one
251-
/// static we DON'T want to deduplicate.
252-
#[used]
253-
static SHARED_OBJECT_ID_REF: u64 = 0;
254-
255-
/// Returns a unique identifier for the current shared object.
256-
pub fn shared_object_id() -> u64 {
257-
&SHARED_OBJECT_ID_REF as *const _ as u64
258-
}
259-
260-
/// Defined to `I` when importing globals, `E` when exporting globals, and `N` otherwise.
261-
#[cfg(feature = "import-globals")]
262-
pub static RUBICON_MODE: &str = "I"; // "import"
263-
264-
/// Defined to `I` when importing globals, `E` when exporting globals, and `N` otherwise.
265-
#[cfg(feature = "export-globals")]
266-
pub static RUBICON_MODE: &str = "E"; // "export"
267-
268-
/// Defined to `I` when importing globals, `E` when exporting globals, and `N` otherwise.
269-
#[cfg(not(any(feature = "import-globals", feature = "export-globals")))]
270-
pub static RUBICON_MODE: &str = "N"; // "normal"
271-
272-
#[cfg(all(feature = "import-globals", feature = "export-globals"))]
273-
compile_error!("The features \"import-globals\" and \"export-globals\" are mutually exclusive");
274-
275-
/// A `u64` whose 24-bit ANSI color is determined by its value.
276-
///
277-
/// Used by the [`soprintln`] macro to visually distinguish shared objects and threads.
278-
pub struct Beacon<'a> {
279-
fg: (u8, u8, u8),
280-
bg: (u8, u8, u8),
281-
name: &'a str,
282-
val: u64,
283-
}
284-
285-
impl<'a> Beacon<'a> {
286-
/// Creates a new `Beacon` from a pointer.
287-
pub fn from_ptr<T>(name: &'a str, ptr: *const T) -> Self {
288-
Self::new(name, ptr as u64)
289-
}
290-
291-
/// Creates a new `Beacon` from a reference.
292-
pub fn from_ref<T>(name: &'a str, r: &T) -> Self {
293-
Self::new(name, r as *const T as u64)
294-
}
295-
296-
/// Creates a new `Beacon` with the given extra string and value.
297-
pub fn new(name: &'a str, u: u64) -> Self {
298-
fn hash(mut x: u64) -> u64 {
299-
const K: u64 = 0x517cc1b727220a95;
300-
x = x.wrapping_mul(K);
301-
x ^= x >> 32;
302-
x = x.wrapping_mul(K);
303-
x ^= x >> 32;
304-
x = x.wrapping_mul(K);
305-
x
306-
}
307-
308-
let hashed_float = (hash(u) as f64) / (u64::MAX as f64);
309-
let h = hashed_float * 360.0;
310-
let s = 50.0;
311-
let l = 70.0;
312-
313-
fn hsl_to_rgb(h: f64, s: f64, l: f64) -> (u8, u8, u8) {
314-
let h = h / 360.0;
315-
let s = s / 100.0;
316-
let l = l / 100.0;
317-
318-
let c = (1.0 - (2.0 * l - 1.0).abs()) * s;
319-
let x = c * (1.0 - ((h * 6.0) % 2.0 - 1.0).abs());
320-
let m = l - c / 2.0;
321-
322-
let (r, g, b) = match (h * 6.0) as u8 {
323-
0 | 6 => (c, x, 0.0),
324-
1 => (x, c, 0.0),
325-
2 => (0.0, c, x),
326-
3 => (0.0, x, c),
327-
4 => (x, 0.0, c),
328-
_ => (c, 0.0, x),
329-
};
330-
331-
(
332-
((r + m) * 255.0) as u8,
333-
((g + m) * 255.0) as u8,
334-
((b + m) * 255.0) as u8,
335-
)
336-
}
337-
338-
let fg = hsl_to_rgb(h, s, l);
339-
let bg = hsl_to_rgb(h, s * 0.8, l * 0.5);
340-
341-
Self {
342-
fg,
343-
bg,
344-
name,
345-
val: u,
346-
}
347-
}
348-
}
349-
350-
impl<'a> std::fmt::Display for Beacon<'a> {
351-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352-
write!(
353-
f,
354-
"\x1b[48;2;{};{};{}m\x1b[38;2;{};{};{}m{}#{:0x}\x1b[0m",
355-
self.bg.0, self.bg.1, self.bg.2, self.fg.0, self.fg.1, self.fg.2, self.name, self.val
356-
)
357-
}
358-
}
359-
360-
/// Prints a message, prefixed with a cycling millisecond timestamp (wraps at 99999),
361-
/// a colorized shared object id, a colorized thread name+id, and the given message.
362-
#[macro_export]
363-
#[cfg(feature = "soprintln")]
364-
macro_rules! soprintln {
365-
($($arg:tt)*) => {
366-
{
367-
use std::sync::atomic::{AtomicBool, Ordering};
368-
static ENV_CHECKED: std::sync::Once = std::sync::Once::new();
369-
static SHOULD_PRINT: AtomicBool = AtomicBool::new(false);
370-
ENV_CHECKED.call_once(|| {
371-
let should_print = std::env::var("SO_PRINTLN").map(|v| v == "1").unwrap_or(false);
372-
SHOULD_PRINT.store(should_print, Ordering::Relaxed);
373-
});
374-
375-
if SHOULD_PRINT.load(Ordering::Relaxed) {
376-
// this formatting is terribly wasteful — PRs welcome
377-
378-
let so_id = $crate::shared_object_id();
379-
let so_mode_and_id = $crate::Beacon::new($crate::RUBICON_MODE, so_id);
380-
let curr_thread = std::thread::current();
381-
let tid = format!("{:?}", curr_thread.id());
382-
// strip `ThreadId(` prefix
383-
let tid = tid.strip_prefix("ThreadId(").unwrap_or(&tid);
384-
// strip `)` suffix
385-
let tid = tid.strip_suffix(")").unwrap_or(&tid);
386-
// parse tid as u64
387-
let tid = tid.parse::<u64>().unwrap_or(0);
388-
389-
let thread_name = curr_thread.name().unwrap_or("<unnamed>");
390-
let thread = $crate::Beacon::new(thread_name, tid);
391-
392-
let timestamp = ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_millis() % 99999;
393-
// FIXME: this is probably not necessary, but without it, rustc complains about
394-
// capturing variables in format_args?
395-
let msg = format!($($arg)*);
396-
eprintln!("{timestamp:05} {so_mode_and_id} {thread} {msg}");
397-
}
398-
}
399-
};
400-
}
401-
402-
/// `soprintln!` prints a message prefixed by a truncated timestamp, shared object ID and thread ID.
403-
///
404-
/// It is costly, which is why it's behind a cargo feature AND an environment variable.
405-
///
406-
/// To see soprintln output, enable the `soprintln` cargo feature, and set the `SO_PRINTLN`
407-
/// environment variable to `1`.
408-
#[macro_export]
409-
#[cfg(not(feature = "soprintln"))]
410-
macro_rules! soprintln {
411-
($($arg:tt)*) => {};
412-
}

rubicon/src/soprintln.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

test-crates/bin/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test-crates/bin/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@ edition = "2021"
66
[dependencies]
77
exports = { version = "0.1.0", path = "../exports" }
88
libloading = "0.8.4"
9-
rubicon = { version = "2.0.0", path = "../../rubicon", features = [
10-
"soprintln",
11-
] }
9+
rubicon = { version = "2.0.0", path = "../../rubicon" }
10+
soprintln = { version = "3.0.0", features = ["print"] }

test-crates/bin/src/main.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::sync::atomic::Ordering;
22

33
use exports::{self as _, mokio};
4-
use rubicon::soprintln;
4+
use soprintln::soprintln;
55

66
fn main() {
7-
std::env::set_var("SO_PRINTLN", "1");
8-
7+
soprintln::init!();
98
let exe_path = std::env::current_exe().expect("Failed to get current exe path");
109
let project_root = exe_path
1110
.parent()

test-crates/mod_a/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test-crates/mod_a/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@ crate-type = ["cdylib"]
88

99
[dependencies]
1010
mokio = { version = "0.1.0", path = "../mokio", features = ["import-globals"] }
11-
rubicon = { version = "2.0.0", path = "../../rubicon", features = [
12-
"soprintln",
13-
] }
11+
rubicon = { version = "2.0.0", path = "../../rubicon" }
12+
soprintln = { version = "3.0.0", features = ["print"] }

test-crates/mod_a/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use rubicon::soprintln;
1+
use soprintln::soprintln;
22
use std::sync::atomic::Ordering;
33

44
#[no_mangle]
55
pub fn init() {
6+
soprintln::init!();
67
mokio::MOKIO_TL1.with(|s| s.fetch_add(1, Ordering::Relaxed));
78
mokio::MOKIO_PL1.fetch_add(1, Ordering::Relaxed);
89
soprintln!("DANGEROUS is now {}", unsafe {

0 commit comments

Comments
 (0)