Funifier

Struct Funifier 

Source
pub struct Funifier { /* private fields */ }
Expand description

All-vCPU fun-mode key + petname dictionary handle. Cheap to clone (everything inside is Copy or 'static); typically constructed once per CLI invocation and reused for every identifier in the dump.

Implementations§

Source§

impl Funifier

Source

pub fn ephemeral() -> Self

Construct a Funifier with a process-fresh random key. Two invocations in the same process give DIFFERENT mappings — callers who need cross-invocation determinism use Self::with_seed instead. Used by callers that just want “produce a fun version of this output” without any need to reproduce the mapping later.

Derives the key from SHA-256 over the process pid and a nanosecond timestamp; no rand/getrandom dependency (see body comment). Two instances in one process differ only via the ns timestamp.

Source

pub fn with_seed(seed: &str) -> Self

Construct a Funifier whose mapping is fully determined by seed. Two invocations with the same seed (in the same binary build) produce identical fun names for the same inputs. Different seeds give independent mappings.

Uses SHA-256 over the fixed FUN_PEPPER || seed bytes, truncated to 128 bits for SipHash — enough for a stable, low-collision fun mapping.

Source

pub fn petname_for(&self, category: &str, payload: &str) -> String

Replace a string identifier with a deterministic adjective-animal pair. The 65 536 (adjective, animal) pairs the dictionary supports give a comfortable margin for dumps with hundreds of distinct identifiers per category — the birthday-paradox collision probability for 100 names drawn from 65k buckets is ~7%, for 50 names ~2%. A future extension could append a 4-digit suffix on collision; for v1 we accept the rare collision.

Examples (with a fixed seed):

let f = Funifier::with_seed("demo");
// Each call yields an adjective-animal pair; the exact
// pair is seed-dependent.
f.petname_for("comm", "ktstr_test_main");
f.petname_for("comm", "scx_simple");
Source

pub fn numeric_id(&self, category: &str, n: u64) -> u64

Replace a u64 identifier with another u64. The mapping is a deterministic permutation per (seed, category): the keyed hash mixes (category, n.to_le_bytes()), and we take the low 64 bits as the new identifier.

The permutation just needs to be deterministic and to rarely collide; fun mode keeps the numbers stable and distinct, not meaningful.

Two distinct (category, n) inputs collide on the same output u64 with probability ~2^-64. Within a single category, n=0 always maps to 0 is NOT guaranteed; consumers that need a sentinel zero should call Self::is_sentinel_u64 or carry the original value out-of-band.

Source

pub fn numeric_id_i64(&self, category: &str, n: i64) -> i64

Replace an i64 identifier (e.g. a kernel pid_t which is signed). Same contract as Self::numeric_id but preserves the i64 zero (since dumps frequently use 0 or -1 as sentinels). Negative values are funified by their absolute value; the sign survives.

Source

pub fn numeric_id_i32(&self, category: &str, n: i32) -> i32

Replace an i32 identifier (e.g. a kernel pid_t / signed uid_t / any 32-bit-wide signed field) with another i32. Same contract as Self::numeric_id_i64 but the output is masked so it fits in 31 bits of magnitude (so a downstream as i32 cast of the funified value can never wrap a high-bit hash output back into the legal i32 range). Sentinels (0, i32::MIN, i32::MAX) round- trip unchanged so failure-dump renderers see the same “kthread / no value” markers in the funified output.

Source

pub fn is_sentinel_i32(n: i32) -> bool

32-bit-wide analog of Self::is_sentinel_u64 for signed 32-bit identifiers. Schemas commonly use 0 for “kernel/unset”, i32::MIN for “no value” / error sentinels, and i32::MAX for “max” markers. Kept distinct from Self::is_sentinel_u32 because the negative sentinel (i32::MIN) has no u32 analog.

Source

pub fn numeric_id_u32(&self, category: &str, n: u32) -> u32

Replace a u32 identifier (e.g. a host CPU number, uid, gid, nlink, or any other 32-bit-wide field) with another u32. Same contract as Self::numeric_id but the output is masked to fit in 32 bits so a downstream consumer that as u32-casts the funified value cannot wrap a high-bit hash output back into the legal 0..=u32::MAX range. Mirror of Self::numeric_id_i64 for the unsigned narrow case.

Sentinel preservation differs from numeric_id: this method preserves both 0 and u32::MAX exactly, since 32-bit identifier schemas frequently use those as sentinels (CPU 0, “no value” 0xFFFFFFFF). Consumers that want the universal u64 sentinel-check semantics call Self::is_sentinel_u64 on the up-cast value, which is equivalent because the u32 sentinels round-trip through the u64 check.

Source

pub fn is_sentinel_u64(n: u64) -> bool

True when the given identifier is “obvious sentinel” — 0 or “max” — and should be passed through unchanged. Lets downstream renderers preserve the failure-dump’s “kthread” vs “pid 0” semantics without leaking real pids.

Source

pub fn is_sentinel_u32(n: u32) -> bool

32-bit-wide analog of Self::is_sentinel_u64 for the narrow u32 paths in Self::numeric_id_u32. Schemas frequently use u32::MAX as the “no value” marker for 32-bit fields and 0 as “kernel / unset”, same shape as the u64 check — kept distinct so downstream callers using numeric_id_u32 don’t have to up-cast just to check.

Source

pub fn is_u32_category(key: &str) -> bool

Categories whose JSON value is u32-width in the originating schema and must be funified through Self::numeric_id_u32 (32-bit-masked output) instead of the default Self::numeric_id (full u64 output).

Why this matters: serde_json’s Value::Number only carries is_u64/is_i64/is_f64, not the original Rust width. When a struct field is typed u32 but serialized through a generic serde_json::Value, the funify walker can’t see the narrowing. A full-u64 funified output then overflows when a downstream consumer (CLI parser, as u32 cast, JSON round-trip into a u32-field struct) narrows it back. Naming the u32-width identifier categories explicitly is the only mechanism available without schema metadata.

The allowlist is conservative: only includes keys whose originating Rust field is documented or named-matchable as u32-wide. New u32 fields added to ktstr’s schemas must be declared here or they fall through to the u64 path and the overflow returns.

Source

pub fn is_metric_passthrough(key: &str) -> bool

Allowlist gate for the funify walker: returns true when the JSON-object key holds a value that is a METRIC (count, rate, ratio, byte/duration unit, structural enum) and should pass through funification unchanged. Returns false for everything else — those values get funified.

Inverted polarity vs. v1: previously a deny-list of known identifier keys (pid/cpu/cgroup/…) selected the funify path. The deny-list missed every novel identifier-shaped field as the schema grew. The allowlist makes the safe default “funify it” — any new or unrecognised field is hidden by default, only metrics whose values are numeric/categorical truth (and therefore safe to retain) pass through.

Match strategy:

  • lowercased-key whole-match against a fixed structural vocabulary (schema/version/type/kind/status/…);
  • suffix-match against unit/quantity vocabulary (_count/_total/_per_sec/_ns/_bytes/_ratio/_pct/…);
  • everything else returns false.

Returns true when key names a metric value.

Trait Implementations§

Source§

impl Clone for Funifier

Source§

fn clone(&self) -> Funifier

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Funifier

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> MaybeSend for T
where T: Send,

§

impl<T> MaybeSend for T
where T: Send,