rdftk_io 0.2.1

This crate provides traits for reading and writing Statements and Graphs as well as implementations of these for common representations.
Documentation
use env_logger::fmt::{Color, Style, StyledValue};
use env_logger::{Builder, WriteStyle};
use log::{Level, LevelFilter};
use std::fmt;
use std::io::Write;
use std::sync::atomic::{AtomicUsize, Ordering};

// ------------------------------------------------------------------------------------------------
// Public Types
// ------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------
// Private Types
// ------------------------------------------------------------------------------------------------

struct Padded<T> {
    value: T,
    width: usize,
}
// ------------------------------------------------------------------------------------------------
// Public Functions
// ------------------------------------------------------------------------------------------------

pub fn try_init() {
    let mut builder = Builder::from_default_env();

    let _ = builder
        .format(|f, record| {
            let target = record.target();
            let max_width = max_target_width(target);

            let mut style = f.style();
            let level = colored_level(&mut style, record.level());

            let mut style = f.style();
            let target = style.set_bold(true).value(Padded {
                value: target,
                width: max_width,
            });

            writeln!(
                f,
                "{} {}{} - {}",
                level,
                target,
                if let Some(line) = record.line() {
                    format!(" [{:0>4}]", line)
                } else {
                    String::new()
                },
                record.args(),
            )
        })
        .filter(None, LevelFilter::Trace)
        .format_timestamp_millis()
        .write_style(WriteStyle::Always)
        .try_init();
}

// ------------------------------------------------------------------------------------------------
// Implementations
// ------------------------------------------------------------------------------------------------

impl<T: fmt::Display> fmt::Display for Padded<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{: <width$}", self.value, width = self.width)
    }
}

// ------------------------------------------------------------------------------------------------
// Private Functions
// ------------------------------------------------------------------------------------------------

static MAX_MODULE_WIDTH: AtomicUsize = AtomicUsize::new(0);

fn max_target_width(target: &str) -> usize {
    let max_width = MAX_MODULE_WIDTH.load(Ordering::Relaxed);
    if max_width < target.len() {
        MAX_MODULE_WIDTH.store(target.len(), Ordering::Relaxed);
        target.len()
    } else {
        max_width
    }
}

fn colored_level<'a>(style: &'a mut Style, level: Level) -> StyledValue<'a, &'static str> {
    match level {
        Level::Trace => style.set_color(Color::Magenta).value("TRACE"),
        Level::Debug => style.set_color(Color::Blue).value("DEBUG"),
        Level::Info => style.set_color(Color::Green).value("INFO "),
        Level::Warn => style.set_color(Color::Yellow).value("WARN "),
        Level::Error => style.set_color(Color::Red).value("ERROR"),
    }
}

// ------------------------------------------------------------------------------------------------
// Modules
// ------------------------------------------------------------------------------------------------