1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
use libc::{c_long, sysconf, _SC_PAGESIZE};
use once_cell::sync::Lazy;
use serde::Serialize;
use tracing::warn;

/// Sensible default for many if not all systems.
const DEFAULT_PAGE_SIZE: usize = 4096;

/// OS page size.
pub static OS_PAGE_SIZE: Lazy<usize> = Lazy::new(|| {
    // https://www.gnu.org/software/libc/manual/html_node/Sysconf.html
    let value: c_long = unsafe { sysconf(_SC_PAGESIZE) };
    if value <= 0 {
        DEFAULT_PAGE_SIZE
    } else {
        value as usize
    }
});

/// Warns if `value` is not a multiple of the OS page size.
pub fn check_multiple_of_page_size(value: usize) {
    if value % *OS_PAGE_SIZE != 0 {
        warn!(
            "maximum size {} is not multiple of system page size {}",
            value, *OS_PAGE_SIZE,
        );
    }
}

/// serializes value to json;
/// pretty_print: false = inline
/// pretty_print: true  = pretty printed / multiline
pub fn jsonify<T>(value: T, pretty_print: bool) -> String
where
    T: Serialize,
{
    let fj = if pretty_print {
        serde_json::to_string_pretty
    } else {
        serde_json::to_string
    };

    match fj(&value) {
        Ok(json) => json,
        Err(_) => r#"{"error": "encountered error serializing value"}"#.to_owned(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde::{Deserialize, Serialize};

    #[derive(Clone, Debug, Deserialize, Eq, Serialize)]
    struct SerMock {
        foo: String,
        bar: u32,
    }

    impl PartialEq for SerMock {
        fn eq(&self, other: &SerMock) -> bool {
            self.foo.eq(&other.foo) && self.bar == other.bar
        }
    }

    #[test]
    fn should_ser_to_json() {
        let sermock = SerMock {
            foo: "foo".to_string(),
            bar: 1,
        };

        let json = jsonify(sermock, false);

        assert_eq!(json, r#"{"foo":"foo","bar":1}"#, "json expected to match");
    }

    #[test]
    fn should_ser_to_pretty_json() {
        let sermock = SerMock {
            foo: "foo".to_string(),
            bar: 1,
        };

        let json = jsonify(sermock, true);

        assert!(json.contains('\n'), "json expected to be multiline");
    }

    #[test]
    fn should_deser_from_json() {
        let sermock = SerMock {
            foo: "foo".to_string(),
            bar: 1,
        };

        let json = jsonify(&sermock, false);

        let sermock_clone: SerMock = serde_json::from_str(&json).expect("should deser");

        assert!(
            sermock.eq(&sermock_clone),
            "instances should contain the same data"
        );
    }
}