j2k-native 0.6.1

Pure-Rust JPEG 2000 and HTJ2K codec engine for j2k
Documentation
#[cfg(feature = "std")]
use core::cell::RefCell;

#[cfg(feature = "std")]
use j2k_profile::{profile_stage_mode_from_env, ProfileStageMode};

#[cfg(feature = "std")]
use std::sync::OnceLock;
#[cfg(feature = "std")]
use std::time::Instant;

#[cfg(all(test, feature = "std"))]
pub(crate) use j2k_profile::ProfileSummary;

#[cfg(feature = "std")]
const PROFILE_ENV_VAR: &str = "J2K_PROFILE_STAGES";

#[cfg(feature = "std")]
#[cfg(test)]
pub(crate) fn parse_profile_env_flag(value: Option<&str>) -> bool {
    j2k_profile::profile_stage_mode_from_value(value) != ProfileStageMode::Disabled
}

#[cfg(feature = "std")]
pub(crate) fn profile_stages_enabled() -> bool {
    profile_stage_mode() != ProfileStageMode::Disabled
}

#[cfg(feature = "std")]
fn profile_stage_mode() -> ProfileStageMode {
    static MODE: OnceLock<ProfileStageMode> = OnceLock::new();
    *MODE.get_or_init(|| profile_stage_mode_from_env(PROFILE_ENV_VAR))
}

#[cfg(not(feature = "std"))]
pub(crate) fn profile_stages_enabled() -> bool {
    false
}

#[cfg(feature = "std")]
pub(crate) type ProfileInstant = Instant;

#[cfg(not(feature = "std"))]
pub(crate) struct ProfileInstant;

#[cfg(feature = "std")]
pub(crate) fn profile_now(enabled: bool) -> Option<ProfileInstant> {
    enabled.then(Instant::now)
}

#[cfg(not(feature = "std"))]
pub(crate) fn profile_now(_enabled: bool) -> Option<ProfileInstant> {
    None
}

#[cfg(feature = "std")]
pub(crate) fn elapsed_us(start: Option<ProfileInstant>) -> u128 {
    start.map_or(0, |start| start.elapsed().as_micros())
}

#[cfg(not(feature = "std"))]
pub(crate) fn elapsed_us(_start: Option<ProfileInstant>) -> u128 {
    0
}

#[cfg(feature = "std")]
pub(crate) fn emit_profile_row(op: &str, path: &str, fields: &[(&str, u128)]) {
    j2k_profile::emit_profile_row_u128(
        profile_stage_mode(),
        &PROFILE_SUMMARY,
        "j2k",
        op,
        path,
        fields,
    );
}

#[cfg(not(feature = "std"))]
pub(crate) fn emit_profile_row(_op: &str, _path: &str, _fields: &[(&str, u128)]) {}

#[cfg(feature = "std")]
thread_local! {
    static PROFILE_SUMMARY: RefCell<j2k_profile::ProfileSummary> =
        RefCell::new(j2k_profile::ProfileSummary::default().emit_on_drop());
}

#[cfg(all(test, feature = "std"))]
mod tests {
    use super::*;

    #[test]
    fn parses_profile_env_flag_when_any_profile_mode_is_enabled() {
        assert!(parse_profile_env_flag(Some("1")));
        assert!(parse_profile_env_flag(Some("true")));
        assert!(parse_profile_env_flag(Some("summary")));
        assert!(parse_profile_env_flag(Some("aggregate")));
        assert!(!parse_profile_env_flag(None));
        assert!(!parse_profile_env_flag(Some("")));
        assert!(!parse_profile_env_flag(Some("0")));
    }

    #[test]
    fn profile_summary_groups_rows_and_averages_timing_fields() {
        let mut summary = ProfileSummary::default();
        summary.record_u128(
            "j2k",
            "encode",
            "cpu",
            &[
                ("deinterleave_us", 10),
                ("dwt_us", 30),
                ("block_encode_us", 60),
                ("total_us", 100),
            ],
        );
        summary.record_u128(
            "j2k",
            "encode",
            "cpu",
            &[
                ("deinterleave_us", 14),
                ("dwt_us", 42),
                ("block_encode_us", 72),
                ("total_us", 128),
            ],
        );

        assert_eq!(
            summary.format_rows(),
            vec![
                "j2k_profile_summary codec=j2k op=encode path=cpu count=2 block_encode_us_sum=132 block_encode_us_avg=66 deinterleave_us_sum=24 deinterleave_us_avg=12 dwt_us_sum=72 dwt_us_avg=36 total_us_sum=228 total_us_avg=114"
            ]
        );
    }
}