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
use std::fmt::Debug;
use std::mem;
use std::os::raw::*;

// This isn't actually the number of the bits in the format.
// X11 does a match on this value to determine which type to call sizeof on.
// Thus, we use 32 for c_long, since 32 maps to c_long which maps to 64.
// ...if that sounds confusing, then you know why this enum is here.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Format {
    Char = 8,
    Short = 16,
    Long = 32,
}

impl Format {
    pub fn from_format(format: usize) -> Option<Self> {
        match format {
            8 => Some(Format::Char),
            16 => Some(Format::Short),
            32 => Some(Format::Long),
            _ => None,
        }
    }

    pub fn is_same_size_as<T>(&self) -> bool {
        mem::size_of::<T>() == self.get_actual_size()
    }

    pub fn get_actual_size(&self) -> usize {
        match self {
            &Format::Char => mem::size_of::<c_char>(),
            &Format::Short => mem::size_of::<c_short>(),
            &Format::Long => mem::size_of::<c_long>(),
        }
    }

    pub fn get_payload_size(&self) -> usize {
        match self {
            // Due to the wonders of X11, half the space goes unused if you're not using longs (on 64-bit).
            &Format::Char => mem::size_of::<c_char>() * 20,
            &Format::Short => mem::size_of::<c_short>() * 10,
            &Format::Long => mem::size_of::<c_long>() * 5,
        }
    }
}

pub trait Formattable: Debug + Clone + Copy + PartialEq + PartialOrd {
    const FORMAT: Format;
}

// You might be surprised by the absence of c_int, but not as surprised as X11 would be by the presence of it.
impl Formattable for c_schar { const FORMAT: Format = Format::Char; }
impl Formattable for c_uchar { const FORMAT: Format = Format::Char; }
impl Formattable for c_short { const FORMAT: Format = Format::Short; }
impl Formattable for c_ushort { const FORMAT: Format = Format::Short; }
impl Formattable for c_long { const FORMAT: Format = Format::Long; }
impl Formattable for c_ulong { const FORMAT: Format = Format::Long; }