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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#![doc(html_root_url = "http://arcnmx.github.io/ddcutil-rs/")]
pub extern crate ddcutil_sys as sys;
extern crate libc;
#[macro_use]
extern crate bitflags;

use std::{result, str};

mod status;
pub use status::{Status, Error};
pub type Result<T> = result::Result<T, Error>;

mod display;
pub use display::*;

mod features;
pub use features::*;

pub type Version = sys::DDCA_Ddcutil_Version_Spec;

unsafe fn c_str<'a>(ptr: *const libc::c_char) -> result::Result<&'a str, str::Utf8Error> {
    use std::ffi::CStr;

    str::from_utf8(CStr::from_ptr(ptr).to_bytes())
}

pub fn version() -> Version {
    unsafe {
        sys::ddca_ddcutil_version()
    }
}

pub fn version_string() -> &'static str {
    unsafe {
        c_str(sys::ddca_ddcutil_version_string())
            .expect("ddcutil returned invalid version string")
    }
}

pub fn verification_enabled() -> bool {
    unsafe {
        sys::ddca_is_verify_enabled()
    }
}

pub fn set_verification(onoff: bool) {
    unsafe {
        sys::ddca_enable_verify(onoff)
    }
}

#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum OutputLevel {
    Terse = sys::DDCA_OL_TERSE as _,
    Normal = sys::DDCA_OL_NORMAL as _,
    Verbose = sys::DDCA_OL_VERBOSE as _,
}

impl Default for OutputLevel {
    fn default() -> Self {
        OutputLevel::Normal
    }
}

impl OutputLevel {
    pub fn from_raw(raw: sys::DDCA_Output_Level) -> result::Result<Self, ()> {
        match raw {
            sys::DDCA_OL_TERSE => Ok(OutputLevel::Terse),
            sys::DDCA_OL_NORMAL => Ok(OutputLevel::Normal),
            sys::DDCA_OL_VERBOSE => Ok(OutputLevel::Verbose),
            _ => Err(()),
        }
    }

    pub fn to_raw(&self) -> sys::DDCA_Output_Level {
        *self as _
    }
}

pub fn output_level() -> OutputLevel {
    unsafe {
        OutputLevel::from_raw(sys::ddca_get_output_level())
            .expect("invalid output level")
    }
}

pub fn set_output_level(value: OutputLevel) {
    unsafe {
        sys::ddca_set_output_level(value.to_raw())
    }
}

#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RetryType {
    WriteOnly = sys::DDCA_WRITE_ONLY_TRIES as _,
    WriteRead = sys::DDCA_WRITE_READ_TRIES as _,
    MultiPart = sys::DDCA_MULTI_PART_TRIES as _,
}

impl RetryType {
    pub fn to_raw(&self) -> sys::DDCA_Retry_Type {
        *self as _
    }
}

pub fn max_retries() -> usize {
    unsafe {
        sys::ddca_max_max_tries() as _
    }
}

pub fn get_retries(ty: RetryType) -> usize {
    unsafe {
        sys::ddca_get_max_tries(ty.to_raw()) as _
    }
}

pub fn set_retries(ty: RetryType, value: usize) -> Result<()> {
    unsafe {
        Error::from_status(sys::ddca_set_max_tries(ty.to_raw(), value as _)).map(drop)
    }
}

#[test]
fn test_api() {
    let _ = version();
    let _ = version_string();
    let _ = output_level();
    let _ = verification_enabled();
    let _ = max_retries();
    for ty in vec![RetryType::WriteOnly, RetryType::WriteRead, RetryType::MultiPart] {
        let _ = get_retries(ty);
    }
}

#[test]
fn test_output_level() {
    for level in vec![OutputLevel::Terse, OutputLevel::Normal, OutputLevel::Verbose] {
        set_output_level(level);
    }
}

#[test]
fn test_retries() {
    let max = max_retries();
    for ty in vec![RetryType::WriteOnly, RetryType::WriteRead, RetryType::MultiPart] {
        for retry in 1..(max + 1) {
            assert!(set_retries(ty, retry).is_ok());
        }
        assert!(set_retries(ty, max + 1).is_err());
    }
}