<commit_before>/// A legacy 16/16 version encoding

/// Packed 32-bit value with major and minor version numbers.
///
/// This is a legacy type with an unusual representation. See [the spec][] for
/// additional details.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Version16Dot16(u32);

/// A type representing a major, minor version pair.
///
/// This is not part of the spec, but versions in the spec are frequently
/// represented as a `major_version`, `minor_version` pair. This type encodes
/// those as a single type, which is useful for some of the generated code that
/// parses out a version.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MajorMinor(u16, u16);

impl Version16Dot16 {
    /// Version 0.5
    pub const VERSION_0_5: Version16Dot16 = Version16Dot16::new(0, 5);
    /// Version 1.0
    pub const VERSION_1_0: Version16Dot16 = Version16Dot16::new(1, 0);
    /// Version 2.0
    pub const VERSION_2_0: Version16Dot16 = Version16Dot16::new(2, 0);
    /// Version 2.5
    pub const VERSION_2_5: Version16Dot16 = Version16Dot16::new(2, 5);
    /// Version 3.0
    pub const VERSION_3_0: Version16Dot16 = Version16Dot16::new(3, 0);

    /// Create a new version with the provided major and minor parts.
    ///
    /// The minor version must be in the range 0..=9.
    ///
    /// # Panics
    ///
    /// Panics if `minor > 9`.
    pub const fn new(major: u16, minor: u16) -> Self {
        assert!(minor < 10, "minor version must be in the range [0, 9)");
        let version = (major as u32) << 16 | (minor as u32) << 12;
        Version16Dot16(version)
    }

    /// Return the separate major & minor version numbers.
    pub const fn to_major_minor(self) -> (u16, u16) {
        let major = (self.0 >> 16) as u16;
        let minor = ((self.0 & 0xFFFF) >> 12) as u16;
        (major, minor)
    }

    /// The representation of this version as a big-endian byte array.
    pub fn to_be_bytes(self) -> [u8; 4] {
        self.0.to_be_bytes()
    }
}

crate::newtype_scalar!(Version16Dot16, [u8; 4]);

impl MajorMinor {
    /// Version 1.0
    pub const VERSION_1_0: MajorMinor = MajorMinor::new(1, 0);
    /// Version 1.1
    pub const VERSION_1_1: MajorMinor = MajorMinor::new(1, 1);
    /// Version 1.2
    pub const VERSION_1_2: MajorMinor = MajorMinor::new(1, 2);
    /// Version 1.3
    pub const VERSION_1_3: MajorMinor = MajorMinor::new(1, 3);

    /// Create a new version with major and minor parts.
    pub const fn new(major: u16, minor: u16) -> Self {
        MajorMinor(major, minor)
    }

    /// `true` if major == major, and self.minor is >= other.minor
    pub const fn compatible(self, other: MajorMinor) -> bool {
        self.0 == other.0 && self.1 >= other.1
    }
}

impl crate::Scalar for MajorMinor {
    type Raw = [u8; 4];

    fn from_raw(raw: Self::Raw) -> Self {
        let major = u16::from_be_bytes([raw[0], raw[1]]);
        let minor = u16::from_be_bytes([raw[2], raw[3]]);
        Self(major, minor)
    }

    fn to_raw(self) -> Self::Raw {
        let [a, b] = self.0.to_be_bytes();
        let [c, d] = self.1.to_be_bytes();
        [a, b, c, d]
    }
}

impl crate::FixedSized for MajorMinor {
    const RAW_BYTE_LEN: usize = 4;
}

impl crate::ReadScalar for MajorMinor {
    #[inline]
    fn read(bytes: &[u8]) -> Option<Self> {
        let major = u16::read(bytes)?;
        let minor = bytes.get(2..).and_then(u16::read)?;
        Some(MajorMinor::new(major, minor))
    }
}

impl std::fmt::Debug for Version16Dot16 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Version16Dot16({:08x})", self.0)
    }
}

impl std::fmt::Display for Version16Dot16 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let (major, minor) = self.to_major_minor();
        write!(f, "{}.{}", major, minor)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn version_smoke_test() {
        assert_eq!(Version16Dot16(0x00005000).to_major_minor(), (0, 5));
        assert_eq!(Version16Dot16(0x00011000).to_major_minor(), (1, 1));
        assert_eq!(Version16Dot16::new(0, 5).0, 0x00005000);
        assert_eq!(Version16Dot16::new(1, 1).0, 0x00011000);
    }
}
<commit_msg>MajorMinor struct gets named fields<commit_after>/// A legacy 16/16 version encoding

/// Packed 32-bit value with major and minor version numbers.
///
/// This is a legacy type with an unusual representation. See [the spec][] for
/// additional details.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Version16Dot16(u32);

/// A type representing a major, minor version pair.
///
/// This is not part of the spec, but versions in the spec are frequently
/// represented as a `major_version`, `minor_version` pair. This type encodes
/// those as a single type, which is useful for some of the generated code that
/// parses out a version.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MajorMinor {
    /// The major version number
    pub major: u16,
    /// The minor version number
    pub minor: u16,
}

impl Version16Dot16 {
    /// Version 0.5
    pub const VERSION_0_5: Version16Dot16 = Version16Dot16::new(0, 5);
    /// Version 1.0
    pub const VERSION_1_0: Version16Dot16 = Version16Dot16::new(1, 0);
    /// Version 2.0
    pub const VERSION_2_0: Version16Dot16 = Version16Dot16::new(2, 0);
    /// Version 2.5
    pub const VERSION_2_5: Version16Dot16 = Version16Dot16::new(2, 5);
    /// Version 3.0
    pub const VERSION_3_0: Version16Dot16 = Version16Dot16::new(3, 0);

    /// Create a new version with the provided major and minor parts.
    ///
    /// The minor version must be in the range 0..=9.
    ///
    /// # Panics
    ///
    /// Panics if `minor > 9`.
    pub const fn new(major: u16, minor: u16) -> Self {
        assert!(minor < 10, "minor version must be in the range [0, 9)");
        let version = (major as u32) << 16 | (minor as u32) << 12;
        Version16Dot16(version)
    }

    /// Return the separate major & minor version numbers.
    pub const fn to_major_minor(self) -> (u16, u16) {
        let major = (self.0 >> 16) as u16;
        let minor = ((self.0 & 0xFFFF) >> 12) as u16;
        (major, minor)
    }

    /// The representation of this version as a big-endian byte array.
    #[inline]
    pub fn to_be_bytes(self) -> [u8; 4] {
        self.0.to_be_bytes()
    }
}

crate::newtype_scalar!(Version16Dot16, [u8; 4]);

impl MajorMinor {
    /// Version 1.0
    pub const VERSION_1_0: MajorMinor = MajorMinor::new(1, 0);
    /// Version 1.1
    pub const VERSION_1_1: MajorMinor = MajorMinor::new(1, 1);
    /// Version 1.2
    pub const VERSION_1_2: MajorMinor = MajorMinor::new(1, 2);
    /// Version 1.3
    pub const VERSION_1_3: MajorMinor = MajorMinor::new(1, 3);

    /// Create a new version with major and minor parts.
    #[inline]
    pub const fn new(major: u16, minor: u16) -> Self {
        MajorMinor { major, minor }
    }

    /// `true` if major == major, and self.minor is >= other.minor
    #[inline]
    pub const fn compatible(self, other: MajorMinor) -> bool {
        self.major == other.major && self.minor >= other.minor
    }

    /// The representation of this version as a big-endian byte array.
    #[inline]
    pub fn to_be_bytes(self) -> [u8; 4] {
        let [a, b] = self.major.to_be_bytes();
        let [c, d] = self.major.to_be_bytes();
        [a, b, c, d]
    }
}

impl crate::Scalar for MajorMinor {
    type Raw = [u8; 4];

    fn from_raw(raw: Self::Raw) -> Self {
        let major = u16::from_be_bytes([raw[0], raw[1]]);
        let minor = u16::from_be_bytes([raw[2], raw[3]]);
        Self { major, minor }
    }

    fn to_raw(self) -> Self::Raw {
        self.to_be_bytes()
    }
}

impl crate::FixedSized for MajorMinor {
    const RAW_BYTE_LEN: usize = 4;
}

impl crate::ReadScalar for MajorMinor {
    #[inline]
    fn read(bytes: &[u8]) -> Option<Self> {
        let major = u16::read(bytes)?;
        let minor = bytes.get(2..).and_then(u16::read)?;
        Some(MajorMinor::new(major, minor))
    }
}

impl std::fmt::Debug for Version16Dot16 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Version16Dot16({:08x})", self.0)
    }
}

impl std::fmt::Display for Version16Dot16 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let (major, minor) = self.to_major_minor();
        write!(f, "{}.{}", major, minor)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn version_smoke_test() {
        assert_eq!(Version16Dot16(0x00005000).to_major_minor(), (0, 5));
        assert_eq!(Version16Dot16(0x00011000).to_major_minor(), (1, 1));
        assert_eq!(Version16Dot16::new(0, 5).0, 0x00005000);
        assert_eq!(Version16Dot16::new(1, 1).0, 0x00011000);
    }
}
<|endoftext|>


<commit_before>const NIL: char = '';

/// The mapping for [code page 850](https://en.wikipedia.org/wiki/Code_page_850)
///
/// This code page is also known as `DOS/IBM-ASCII` and is used as the default
/// code page by this library.
pub const CODEPAGE_0850: &'static [char]  = &[
//   0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    NIL,  '☺',  '☻',  '♥',  '♦',  '♣',  '♠',  '•',  '◘',  '○',  '◙',  '♂',  '♀',  '♪',  '♫',  '☼', // 0
    '►',  '◄',  '↕',  '‼',  '¶',  '§',  '▬',  '↨',  '↑',  '↓',  '→',  '←',  '∟',  '↔',  '▲',  '▼', // 1
    ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/', // 2
    '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?', // 3
    '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O', // 4
    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_', // 5
    '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o', // 6
    'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z',  '{',  '|',  '}',  '~',  '⌂', // 7
    'Ç',  'ü',  'é',  'â',  'ä',  'à',  'å',  'ç',  'ê',  'ë',  'è',  'ï',  'î',  'ì',  'Ä',  'Å', // 8
    'É',  'æ',  'Æ',  'ô',  'ö',  'ò',  'û',  'ù',  'ÿ',  'Ö',  'Ü',  'ø',  '£',  'Ø',  '×',  'ƒ', // 9
    'á',  'í',  'ó',  'ú',  'ñ',  'Ñ',  'ª',  'º',  '¿',  '⌐',  '¬',  '½',  '¼',  '¡',  '«',  '»', // A
    '░',  '▒',  '▓',  '│',  '┤',  '╡',  '╢',  '╖',  '╕',  '╣',  '║',  '╗',  '╝',  '╜',  '╛',  '┐', // B
    '└',  '┴',  '┬',  '├',  '─',  '┼',  '╞',  '╟',  '╚',  '╔',  '╩',  '╦',  '╠',  '═',  '╬',  '╧', // C
    '╨',  '╤',  '╥',  '╙',  '╘',  '╒',  '╕',  '╫',  '╪',  '┘',  '┌',  '█',  '▄',  '▌',  '▐',  '▀', // D
    'α',  'ß',  'Γ',  '∏',  '∑',  'σ',  'µ',  'τ',  'Φ',  'θ',  'Ω',  'δ',  '∞',  'Ø',  'ε',  '∩', // E
    '≡',  '±',  '≥',  '≤',  '⌠',  '⌡',  '÷',  '≈',  '▫',  '¨',  '·',  '√',  'ⁿ',  '²',  '■',  NIL, // F
];

/// The mapping for [code page 1252](https://en.wikipedia.org/wiki/Code_page_1252)
///
/// This code page is also known as `Latin 1 Windows` or `ANSI`.
pub const CODEPAGE_1252: &'static [char] = &[
//   0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL, // 0
    NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL, // 1
    ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/', // 2
    '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?', // 3
    '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O', // 4
    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_', // 5
    '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o', // 6
    'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z',  '{',  '|',  '}',  '~',  NIL, // 7
    '€',  NIL,  '‚',  'ƒ',  '„',  '…',  '†',  '‡',  'ˆ',  '‰',  'Š',  '‹',  'Œ',  NIL,  'Ž',  NIL, // 8
    NIL,  '‘',  '’',  '“',  '”',  '•',  '–',  '—',  '˜',  '™',  'Š',  '›',  'œ',  NIL,  'ž',  'Ÿ', // 9
    ' ',  '¡',  '¢',  '£',  '¤',  '¥',  '¦',  '§',  '¨',  '©',  'ª',  '«',  '¬',  NIL,  '®',  '¯', // A
    '°',  '±',  '²',  '³',  '´',  'µ',  '¶',  '·',  '¸',  '¹',  'º',  '»',  '¼',  '½',  '¾',  '¿', // B
    'À',  'Á',  'Â',  'Ã',  'Ä',  'Å',  'Æ',  'Ç',  'È',  'É',  'Ê',  'Ë',  'Ì',  'Í',  'Î',  'Ï', // C
    'Ð',  'Ñ',  'Ò',  'Ó',  'Ô',  'Õ',  'Ö',  '×',  'Ø',  'Ù',  'Ú',  'Û',  'Ü',  'Ý',  'Þ',  'ß', // D
    'à',  'á',  'â',  'ã',  'ä',  'å',  'æ',  'ç',  'è',  'é',  'ê',  'ë',  'ì',  'í',  'î',  'ï', // E
    'ð',  'ñ',  'ò',  'ó',  'ô',  'õ',  'ö',  '÷',  'ø',  'ù',  'ú',  'û',  'ü',  'ý',  'þ',  'ÿ', // F
];

fn contains(byte: u8, codepage: &[char]) -> bool {
    (byte as usize) < codepage.len()
}

/// Returns a byte's character representation given a specific codepage
pub fn as_char(byte: u8, codepage: &[char]) -> char {
    if !contains(byte, codepage) {
        return NIL;
    }

    codepage[byte as usize]
}
<commit_msg>[impl] Use rust's REPLACEMENT_CHARACTER as fallback character<commit_after>use std;

const NIL: char = std::char::REPLACEMENT_CHARACTER;

/// The mapping for [code page 850](https://en.wikipedia.org/wiki/Code_page_850)
///
/// This code page is also known as `DOS/IBM-ASCII` and is used as the default
/// code page by this library.
pub const CODEPAGE_0850: &'static [char]  = &[
//   0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    NIL,  '☺',  '☻',  '♥',  '♦',  '♣',  '♠',  '•',  '◘',  '○',  '◙',  '♂',  '♀',  '♪',  '♫',  '☼', // 0
    '►',  '◄',  '↕',  '‼',  '¶',  '§',  '▬',  '↨',  '↑',  '↓',  '→',  '←',  '∟',  '↔',  '▲',  '▼', // 1
    ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/', // 2
    '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?', // 3
    '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O', // 4
    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_', // 5
    '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o', // 6
    'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z',  '{',  '|',  '}',  '~',  '⌂', // 7
    'Ç',  'ü',  'é',  'â',  'ä',  'à',  'å',  'ç',  'ê',  'ë',  'è',  'ï',  'î',  'ì',  'Ä',  'Å', // 8
    'É',  'æ',  'Æ',  'ô',  'ö',  'ò',  'û',  'ù',  'ÿ',  'Ö',  'Ü',  'ø',  '£',  'Ø',  '×',  'ƒ', // 9
    'á',  'í',  'ó',  'ú',  'ñ',  'Ñ',  'ª',  'º',  '¿',  '⌐',  '¬',  '½',  '¼',  '¡',  '«',  '»', // A
    '░',  '▒',  '▓',  '│',  '┤',  '╡',  '╢',  '╖',  '╕',  '╣',  '║',  '╗',  '╝',  '╜',  '╛',  '┐', // B
    '└',  '┴',  '┬',  '├',  '─',  '┼',  '╞',  '╟',  '╚',  '╔',  '╩',  '╦',  '╠',  '═',  '╬',  '╧', // C
    '╨',  '╤',  '╥',  '╙',  '╘',  '╒',  '╕',  '╫',  '╪',  '┘',  '┌',  '█',  '▄',  '▌',  '▐',  '▀', // D
    'α',  'ß',  'Γ',  '∏',  '∑',  'σ',  'µ',  'τ',  'Φ',  'θ',  'Ω',  'δ',  '∞',  'Ø',  'ε',  '∩', // E
    '≡',  '±',  '≥',  '≤',  '⌠',  '⌡',  '÷',  '≈',  '▫',  '¨',  '·',  '√',  'ⁿ',  '²',  '■',  NIL, // F
];

/// The mapping for [code page 1252](https://en.wikipedia.org/wiki/Code_page_1252)
///
/// This code page is also known as `Latin 1 Windows` or `ANSI`.
pub const CODEPAGE_1252: &'static [char] = &[
//   0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL, // 0
    NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL,  NIL, // 1
    ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/', // 2
    '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?', // 3
    '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O', // 4
    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_', // 5
    '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o', // 6
    'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z',  '{',  '|',  '}',  '~',  NIL, // 7
    '€',  NIL,  '‚',  'ƒ',  '„',  '…',  '†',  '‡',  'ˆ',  '‰',  'Š',  '‹',  'Œ',  NIL,  'Ž',  NIL, // 8
    NIL,  '‘',  '’',  '“',  '”',  '•',  '–',  '—',  '˜',  '™',  'Š',  '›',  'œ',  NIL,  'ž',  'Ÿ', // 9
    ' ',  '¡',  '¢',  '£',  '¤',  '¥',  '¦',  '§',  '¨',  '©',  'ª',  '«',  '¬',  NIL,  '®',  '¯', // A
    '°',  '±',  '²',  '³',  '´',  'µ',  '¶',  '·',  '¸',  '¹',  'º',  '»',  '¼',  '½',  '¾',  '¿', // B
    'À',  'Á',  'Â',  'Ã',  'Ä',  'Å',  'Æ',  'Ç',  'È',  'É',  'Ê',  'Ë',  'Ì',  'Í',  'Î',  'Ï', // C
    'Ð',  'Ñ',  'Ò',  'Ó',  'Ô',  'Õ',  'Ö',  '×',  'Ø',  'Ù',  'Ú',  'Û',  'Ü',  'Ý',  'Þ',  'ß', // D
    'à',  'á',  'â',  'ã',  'ä',  'å',  'æ',  'ç',  'è',  'é',  'ê',  'ë',  'ì',  'í',  'î',  'ï', // E
    'ð',  'ñ',  'ò',  'ó',  'ô',  'õ',  'ö',  '÷',  'ø',  'ù',  'ú',  'û',  'ü',  'ý',  'þ',  'ÿ', // F
];

fn contains(byte: u8, codepage: &[char]) -> bool {
    (byte as usize) < codepage.len()
}

/// Returns a byte's character representation given a specific codepage
pub fn as_char(byte: u8, codepage: &[char]) -> char {
    if !contains(byte, codepage) {
        return NIL;
    }

    codepage[byte as usize]
}
<|endoftext|>


<commit_before>extern crate libc;
use self::libc::c_int;

static mut callback:Option<extern fn(c_int)> = None;

#[no_mangle]
pub fn rs_trigger(val:c_int) {
  println!("Trigger called");
  if val == 1 {
    println!("Invoking callback");
    unsafe {
      match callback {
        Some(ref cb) => {
          (*cb)(100);
        },
        _ => {
          println!("No callback bound");
        }
      }
    }
  }
  else {
    println!("Nope");
  }
}

#[no_mangle]
pub fn rs_register(cb: extern fn(c_int)) {
  println!("Register called");
  unsafe {
    callback = Some(cb);
  }
}
<commit_msg>match c code for compatibility testing<commit_after>extern crate libc;
use self::libc::c_int;

static mut callback:Option<extern fn(c_int)> = None;

#[no_mangle]
pub fn rs_trigger(val:c_int) -> c_int {
  println!("Trigger called");
  if val == 1 {
    println!("Invoking callback");
    unsafe {
      match callback {
        Some(ref cb) => {
          (*cb)(100);
        },
        _ => {
          println!("No callback bound");
        }
      }
    }
  }
  else {
    println!("Nope");
  }
  return val + 100;
}

#[no_mangle]
pub fn rs_register(cb: extern fn(c_int)) {
  println!("Register called");
  unsafe {
    callback = Some(cb);
  }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use phf_shared::{self, FmtConst};
use serde_json::{self, Value};
use std::env;
use std::fmt;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::time::Instant;

fn main() {
    let start = Instant::now();

    let style_out_dir = PathBuf::from(env::var_os("DEP_SERVO_STYLE_CRATE_OUT_DIR").unwrap());
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    let status = Command::new(find_python())
        .arg("dom/bindings/codegen/run.py")
        .arg(style_out_dir.join("css-properties.json"))
        .arg(&out_dir)
        .status()
        .unwrap();
    if !status.success() {
        std::process::exit(1)
    }

    println!("Binding generation completed in {:?}", start.elapsed());

    let json = out_dir.join("InterfaceObjectMapData.json");
    let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap();
    let mut map = phf_codegen::Map::new();
    for (key, value) in json.as_object().unwrap() {
        map.entry(Bytes(key), value.as_str().unwrap());
    }
    let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
    let mut phf = File::create(&phf).unwrap();
    write!(
        &mut phf,
        "pub static MAP: phf::Map<&'static [u8], fn(JSContext, HandleObject)> = {};\n",
        map.build(),
    )
    .unwrap();
}

#[derive(Eq, Hash, PartialEq)]
struct Bytes<'a>(&'a str);

impl<'a> FmtConst for Bytes<'a> {
    fn fmt_const(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        // https://github.com/rust-lang/rust/issues/55223
        // should technically be just `write!(formatter, "b\"{}\"", self.0)
        // but the referenced issue breaks promotion in the surrounding code
        write!(formatter, "{{ const FOO: &[u8] = b\"{}\"; FOO }}", self.0)
    }
}

impl<'a> phf_shared::PhfHash for Bytes<'a> {
    fn phf_hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
        self.0.as_bytes().phf_hash(hasher)
    }
}

fn find_python() -> String {
    env::var("PYTHON").ok().unwrap_or_else(|| {
        let candidates = if cfg!(windows) {
            ["python2.7.exe", "python27.exe", "python.exe"]
        } else {
            ["python2.7", "python2", "python"]
        };
        for &name in &candidates {
            if Command::new(name)
                .arg("--version")
                .output()
                .ok()
                .map_or(false, |out| out.status.success())
            {
                return name.to_owned();
            }
        }
        panic!(
            "Can't find python (tried {})! Try fixing PATH or setting the PYTHON env var",
            candidates.join(", ")
        )
    })
}
<commit_msg>Use PYTHON2 variable for script's codegen.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use phf_shared::{self, FmtConst};
use serde_json::{self, Value};
use std::env;
use std::fmt;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use std::time::Instant;

fn main() {
    let start = Instant::now();

    let style_out_dir = PathBuf::from(env::var_os("DEP_SERVO_STYLE_CRATE_OUT_DIR").unwrap());
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    let status = Command::new(find_python())
        .arg("dom/bindings/codegen/run.py")
        .arg(style_out_dir.join("css-properties.json"))
        .arg(&out_dir)
        .status()
        .unwrap();
    if !status.success() {
        std::process::exit(1)
    }

    println!("Binding generation completed in {:?}", start.elapsed());

    let json = out_dir.join("InterfaceObjectMapData.json");
    let json: Value = serde_json::from_reader(File::open(&json).unwrap()).unwrap();
    let mut map = phf_codegen::Map::new();
    for (key, value) in json.as_object().unwrap() {
        map.entry(Bytes(key), value.as_str().unwrap());
    }
    let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
    let mut phf = File::create(&phf).unwrap();
    write!(
        &mut phf,
        "pub static MAP: phf::Map<&'static [u8], fn(JSContext, HandleObject)> = {};\n",
        map.build(),
    )
    .unwrap();
}

#[derive(Eq, Hash, PartialEq)]
struct Bytes<'a>(&'a str);

impl<'a> FmtConst for Bytes<'a> {
    fn fmt_const(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        // https://github.com/rust-lang/rust/issues/55223
        // should technically be just `write!(formatter, "b\"{}\"", self.0)
        // but the referenced issue breaks promotion in the surrounding code
        write!(formatter, "{{ const FOO: &[u8] = b\"{}\"; FOO }}", self.0)
    }
}

impl<'a> phf_shared::PhfHash for Bytes<'a> {
    fn phf_hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
        self.0.as_bytes().phf_hash(hasher)
    }
}

fn find_python() -> String {
    env::var("PYTHON2").ok().unwrap_or_else(|| {
        let candidates = if cfg!(windows) {
            ["python2.7.exe", "python27.exe", "python.exe"]
        } else {
            ["python2.7", "python2", "python"]
        };
        for &name in &candidates {
            if Command::new(name)
                .arg("--version")
                .output()
                .ok()
                .map_or(false, |out| out.status.success())
            {
                return name.to_owned();
            }
        }
        panic!(
            "Can't find python (tried {})! Try fixing PATH or setting the PYTHON env var",
            candidates.join(", ")
        )
    })
}
<|endoftext|>


<commit_before>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue), // args, body
	// XXX: we need the symbol table to be a @-ptr
	// otherwise we can't mutate it. &-ptrs give lifetime
	// headaches, and ~-ptrs give move headaches.
	BIF(~str, ~[~str], extern fn(@mut HashMap<~str, ~LispValue>, ~[~LispValue])->~LispValue) // built-in function (args, closure)
}

// XXX: this is ugly but it won't automatically derive Eq because of the extern fn
impl Eq for LispValue {
	fn eq(&self, other: &LispValue) -> bool {
		match (self.clone(), other.clone()) {
			(BIF(ref x, _, _), BIF(ref y, _, _)) if *x == *y => true,
			(Str(ref x), Str(ref y)) if *x == *y => true,
			(Num(ref x), Num(ref y)) if *x == *y => true,
			(Atom(ref x), Atom(ref y)) if *x == *y => true,
			(List(ref x), List(ref y)) if *x == *y => true,
			(Fn(ref x, ref x2), Fn(ref y, ref y2)) if *x == *y && *x2 == *y2 => true,
			_ => false
		}
	}
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Returns a value representing the empty list
#[inline]
pub fn nil() -> ~LispValue {
	~List(~[])
}

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: @mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: @mut SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

/// Identity function
fn id_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue { v[0] }

fn cons_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	~List(~[*v[0].clone(), *v[1].clone()])
}

fn car_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => {
			~v_[0]
		}
		_ => fail!("car: need a list")
	}
}

fn cdr_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(ref v_) => {
			~List(v_.slice(1, v_.len()).to_owned())
		}
		_ => fail!("cdr: need a list")
	}
}

// Print function
fn print_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~Str(s) => printfln!("%s", s),
		_ => fail!("print takes an str")
	}
	nil()
}

/// Initializes standard library functions
pub fn init_std(symt: @mut SymbolTable) {
	bind(symt, ~"id", ~BIF(~"id", ~[~"x"], id_));
	bind(symt, ~"print", ~BIF(~"print", ~[~"msg"], print_));
	bind(symt, ~"cons", ~BIF(~"cons", ~[~"x", ~"y"], cons_));
	bind(symt, ~"car", ~BIF(~"car", ~[~"x"], car_));
	bind(symt, ~"cdr", ~BIF(~"cdr", ~[~"x"], cdr_));
}

fn apply(symt: @mut SymbolTable, f: ~LispValue, args: ~[~LispValue]) -> ~LispValue {
	match *f {
		BIF(name, fnargs, bif) => {
			// apply built-in function
			if fnargs.len() != args.len() {
				fail!("function '%s' requires %u arguments, but it received %u arguments",
					name, fnargs.len(), args.len())
			}

			bif(symt, args)
		}

		_ => fail!("apply: need function")
	}
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: @mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// XXX: If we don't clone, the `match` partially moves v,
			// so we can't use it in the match arms.
			let v_ = v.clone();

			// evaluate a list as a function call
			match v[0] {
				sexpr::Atom(sym) => {
					let f = lookup(symt, sym);
					let args = v_.slice(1, v_.len());
					let xargs = args.map(|x| eval(symt, x.clone())); // eval'd args
					apply(symt, f, xargs)
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use sexpr;
	use sexpr::from_str;

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("123")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id 123)")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id (id (id 123)))")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_cons() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cons 1 2)")), ~List(~[Num(1.0), Num(2.0)]));
		assert_eq!(eval(symt, read("(cons 1 (cons 2 3))")), ~List(~[Num(1.0),
			List(~[Num(2.0), Num(3.0)])]));
	}
}<commit_msg>fix cdr, add tests for car and cdr<commit_after>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue), // args, body
	// XXX: we need the symbol table to be a @-ptr
	// otherwise we can't mutate it. &-ptrs give lifetime
	// headaches, and ~-ptrs give move headaches.
	BIF(~str, ~[~str], extern fn(@mut HashMap<~str, ~LispValue>, ~[~LispValue])->~LispValue) // built-in function (args, closure)
}

// XXX: this is ugly but it won't automatically derive Eq because of the extern fn
impl Eq for LispValue {
	fn eq(&self, other: &LispValue) -> bool {
		match (self.clone(), other.clone()) {
			(BIF(ref x, _, _), BIF(ref y, _, _)) if *x == *y => true,
			(Str(ref x), Str(ref y)) if *x == *y => true,
			(Num(ref x), Num(ref y)) if *x == *y => true,
			(Atom(ref x), Atom(ref y)) if *x == *y => true,
			(List(ref x), List(ref y)) if *x == *y => true,
			(Fn(ref x, ref x2), Fn(ref y, ref y2)) if *x == *y && *x2 == *y2 => true,
			_ => false
		}
	}
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Returns a value representing the empty list
#[inline]
pub fn nil() -> ~LispValue {
	~List(~[])
}

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: @mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: @mut SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

/// Identity function
fn id_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue { v[0] }

fn cons_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	~List(~[*v[0].clone(), *v[1].clone()])
}

fn car_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => {
			~v_[0]
		}
		_ => fail!("car: need a list")
	}
}

fn cdr_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => {
			~v_[1]
		}
		_ => fail!("cdr: need a list")
	}
}

// Print function
fn print_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~Str(s) => printfln!("%s", s),
		_ => fail!("print takes an str")
	}
	nil()
}

/// Initializes standard library functions
pub fn init_std(symt: @mut SymbolTable) {
	bind(symt, ~"id", ~BIF(~"id", ~[~"x"], id_));
	bind(symt, ~"print", ~BIF(~"print", ~[~"msg"], print_));
	bind(symt, ~"cons", ~BIF(~"cons", ~[~"x", ~"y"], cons_));
	bind(symt, ~"car", ~BIF(~"car", ~[~"x"], car_));
	bind(symt, ~"cdr", ~BIF(~"cdr", ~[~"x"], cdr_));
}

fn apply(symt: @mut SymbolTable, f: ~LispValue, args: ~[~LispValue]) -> ~LispValue {
	match *f {
		BIF(name, fnargs, bif) => {
			// apply built-in function
			if fnargs.len() != args.len() {
				fail!("function '%s' requires %u arguments, but it received %u arguments",
					name, fnargs.len(), args.len())
			}

			bif(symt, args)
		}

		_ => fail!("apply: need function")
	}
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: @mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// XXX: If we don't clone, the `match` partially moves v,
			// so we can't use it in the match arms.
			let v_ = v.clone();

			// evaluate a list as a function call
			match v[0] {
				sexpr::Atom(sym) => {
					let f = lookup(symt, sym);
					let args = v_.slice(1, v_.len());
					let xargs = args.map(|x| eval(symt, x.clone())); // eval'd args
					apply(symt, f, xargs)
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use sexpr;
	use sexpr::from_str;

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("123")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id 123)")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id (id (id 123)))")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_cons() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cons 1 2)")), ~List(~[Num(1.0), Num(2.0)]));
		assert_eq!(eval(symt, read("(cons 1 (cons 2 3))")), ~List(~[Num(1.0),
			List(~[Num(2.0), Num(3.0)])]));
	}

	#[test]
	fn test_car() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(car (cons 1 2))")), ~Num(1.0));
	}

	#[test]
	fn test_cdr() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cdr (cons 1 2))")), ~Num(2.0));
		assert_eq!(eval(symt, read("(cdr (cons 1 (cons 2 3)))")), ~List(~[Num(2.0), Num(3.0)]));
	}
}<|endoftext|>


<commit_before>use crate::types::{get_value_from_input_event, Msg};
use web_sys::HtmlInputElement;
use yew::prelude::*;

pub struct CommandLine {
    valid_entries: Vec<Entry>,
    // Among valid (filtered) entries.
    selected_command_index: usize,
    value: String,
}

#[derive(PartialEq, Clone, Properties, Debug)]
pub struct CommandLineProperties {
    pub value: String,
    pub entries: Vec<Entry>,
    pub enabled: bool,
    pub input_node_ref: NodeRef,
    #[prop_or_default]
    pub oninput: Callback<String>,
    #[prop_or_default]
    pub onselect: Callback<Msg>,
    #[prop_or_default]
    pub onenter: Callback<()>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Entry {
    pub label: String,
    pub description: String,
    pub action: Msg,
    pub valid_classes: Vec<String>,
}

#[derive(Debug)]
pub enum CommandLineMsg {
    Noop,
    Click,
    Key(KeyboardEvent),
    Input(String),
}

impl Component for CommandLine {
    type Message = CommandLineMsg;
    type Properties = CommandLineProperties;

    fn create(ctx: &Context<Self>) -> Self {
        Self {
            valid_entries: ctx.props().entries.clone(),
            selected_command_index: 0,
            value: ctx.props().value.clone(),
        }
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        let props = ctx.props();
        let value = &self.value;
        let enabled = props.enabled;
        let valid_entries = &self.valid_entries;
        let selected_entry = valid_entries.get(self.selected_command_index);
        let selected_entry_suffix = selected_entry
            .cloned()
            .map(|v| v.label.clone())
            .unwrap_or_default()
            .strip_prefix(value)
            .map(|v| v.to_string())
            .unwrap_or_default();
        let selected = true;
        // TODO: Fuzzy search.
        let entries: Vec<_> = if selected {
            valid_entries
                .iter()
                .enumerate()
                .map(|(i, v)| {
                    let value_string = v.label.clone();
                    let value_suffix = value_string.strip_prefix(value).unwrap_or_default();

                    // let node = v.to_node();
                    let action = v.action.clone();
                    let onselect = props.onselect.clone();
                    let onclick = ctx.link().callback(move |_e: MouseEvent| {
                        onselect.emit(action.clone());
                        CommandLineMsg::Noop
                    });
                    let mut classes_item = vec!["block", "border"];
                    if i == self.selected_command_index {
                        classes_item.push("selected");
                    }
                    // Avoid re-selecting the node, we want to move to next.
                    html! {

                          { value.clone() }
                          { value_suffix }

                    }
                })
                .collect()
        } else {
            vec![]
        };
        let classes_dropdown = vec!["absolute", "z-10", "bg-white"];
        // let id = view::command_input_id(&path);
        let style = if value.len() > 0 {
            format!("width: {}ch;", value.len())
        } else {
            "width: 0.1ch;".to_string()
        };
        let rows = value.split('\n').count();
        // XXX: Chrome inspector CSS color editor.
        let placeholder = "";
        let placeholder = if placeholder.is_empty() {
            None
        } else {
            Some(html! {

{ placeholder }

            })
        };
        let suffix = if selected {
            selected_entry_suffix
        } else {
            "".to_string()
        };
        let mut class = vec![
            "inline-flex",
            "w-full",
            "bg-transparent",
            "resize-none",
            "overflow-hidden",
        ];
        // let errors = vec![];
        // if !errors.is_empty() {
        //     class.push("error");
        // }

        // let editing = if model.mode == crate::types::Mode::Edit {
        let dropdown = if enabled && selected {
            html! {

                    { for entries }

            }
        } else {
            html! {}
        };
        let suffix = if enabled && selected {
            html! {
                { suffix }
            }
        } else {
            html! {}
        };
        let classes = if enabled && selected {
            match selected_entry {
                Some(entry) => entry.valid_classes.clone().join(" "),
                None => "".to_string(),
            }
        } else {
            "".to_string()
        };

        let oninput = props.oninput.clone();
        let oninput = ctx.link().callback(move |e: InputEvent| {
            let v = get_value_from_input_event(e);
            oninput.emit(v.clone());
            CommandLineMsg::Input(v)
        });

        let onclick = ctx.link().callback(|_| CommandLineMsg::Click);
        let onfocus = ctx.link().callback(|_| CommandLineMsg::Click);
        let onkeydown = ctx
            .link()
            .callback(move |e: KeyboardEvent| CommandLineMsg::Key(e));

        html! {

                { for placeholder }

                        <textarea
                        rows={ format!("{}", rows) }
                        ref={ ctx.props().input_node_ref.clone() }
                        //   id={ id }
                        class={ class }
                        type="text"
                        oninput={ oninput }
                        onkeydown={ onkeydown }
                        //   onfocus={ onfocus }
                        value={ value.to_string() }
                        style={ style }
                        //   disabled={ model.mode != crate::types::Mode::Edit }
                        autocomplete="off"
                        >
                        </textarea>
                        { suffix }

                    { dropdown }

        }
    }

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            CommandLineMsg::Noop => false,
            CommandLineMsg::Click => {
                let input_node = ctx.props().input_node_ref.clone();
                input_node
                    .cast::<HtmlInputElement>()
                    .unwrap()
                    .focus()
                    .unwrap();
                true
            }
            CommandLineMsg::Input(value) => {
                self.value = value.clone();
                self.valid_entries = ctx
                    .props()
                    .entries
                    .clone()
                    .into_iter()
                    .filter(|v| v.label.starts_with(&value))
                    .collect();
                true
            }
            CommandLineMsg::Key(e) => {
                let props = ctx.props();
                let entries = &self.valid_entries;
                let selected_command_index = self.selected_command_index;
                if e.shift_key() {
                    return false;
                }
                match e.key().as_ref() {
                    "ArrowUp" => {
                        if entries.len() > 0 {
                            self.selected_command_index = if selected_command_index > 0 {
                                selected_command_index - 1
                            } else {
                                entries.len() - 1
                            }
                        }
                    }
                    "ArrowDown" => {
                        if entries.len() > 0 {
                            self.selected_command_index =
                                if selected_command_index < entries.len() - 1 {
                                    selected_command_index + 1
                                } else {
                                    0
                                }
                        }
                    }
                    "Enter" => {
                        e.prevent_default();
                        let selected_entry = entries.get(selected_command_index).cloned();
                        if let Some(selected_entry) = selected_entry {
                            let action = selected_entry.action.clone();
                            props.onselect.emit(action);
                        } else {
                            props.onenter.emit(());
                        }
                    }
                    _ => {}
                };
                true
            }
        }
    }
}
<commit_msg>Width<commit_after>use crate::types::{get_value_from_input_event, Msg};
use web_sys::HtmlInputElement;
use yew::prelude::*;

pub struct CommandLine {
    valid_entries: Vec<Entry>,
    // Among valid (filtered) entries.
    selected_command_index: usize,
    value: String,
}

#[derive(PartialEq, Clone, Properties, Debug)]
pub struct CommandLineProperties {
    pub value: String,
    pub entries: Vec<Entry>,
    pub enabled: bool,
    pub input_node_ref: NodeRef,
    #[prop_or_default]
    pub oninput: Callback<String>,
    #[prop_or_default]
    pub onselect: Callback<Msg>,
    #[prop_or_default]
    pub onenter: Callback<()>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Entry {
    pub label: String,
    pub description: String,
    pub action: Msg,
    pub valid_classes: Vec<String>,
}

#[derive(Debug)]
pub enum CommandLineMsg {
    Noop,
    Click,
    Key(KeyboardEvent),
    Input(String),
}

impl Component for CommandLine {
    type Message = CommandLineMsg;
    type Properties = CommandLineProperties;

    fn create(ctx: &Context<Self>) -> Self {
        Self {
            valid_entries: ctx.props().entries.clone(),
            selected_command_index: 0,
            value: ctx.props().value.clone(),
        }
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        let props = ctx.props();
        let value = &self.value;
        let enabled = props.enabled;
        let valid_entries = &self.valid_entries;
        let selected_entry = valid_entries.get(self.selected_command_index);
        let selected_entry_suffix = selected_entry
            .cloned()
            .map(|v| v.label.clone())
            .unwrap_or_default()
            .strip_prefix(value)
            .map(|v| v.to_string())
            .unwrap_or_default();
        let selected = true;
        // TODO: Fuzzy search.
        let entries: Vec<_> = if selected {
            valid_entries
                .iter()
                .enumerate()
                .map(|(i, v)| {
                    let value_string = v.label.clone();
                    let value_suffix = value_string.strip_prefix(value).unwrap_or_default();

                    // let node = v.to_node();
                    let action = v.action.clone();
                    let onselect = props.onselect.clone();
                    let onclick = ctx.link().callback(move |_e: MouseEvent| {
                        onselect.emit(action.clone());
                        CommandLineMsg::Noop
                    });
                    let mut classes_item = vec!["block", "border"];
                    if i == self.selected_command_index {
                        classes_item.push("selected");
                    }
                    // Avoid re-selecting the node, we want to move to next.
                    html! {

                          { value.clone() }
                          { value_suffix }

                    }
                })
                .collect()
        } else {
            vec![]
        };
        let classes_dropdown = vec!["absolute", "z-10", "bg-white"];
        // let id = view::command_input_id(&path);
        let style = if value.len() > 0 {
            format!("width: {}ch;", value.len())
        } else {
            "width: 0.1ch;".to_string()
        };
        let rows = value.split('\n').count();
        // XXX: Chrome inspector CSS color editor.
        let placeholder = "";
        let placeholder = if placeholder.is_empty() {
            None
        } else {
            Some(html! {

{ placeholder }

            })
        };
        let suffix = if selected {
            selected_entry_suffix
        } else {
            "".to_string()
        };
        let mut class = vec![
            "inline-flex",
            "w-full",
            "bg-transparent",
            "resize-none",
            "overflow-hidden",
        ];
        // let errors = vec![];
        // if !errors.is_empty() {
        //     class.push("error");
        // }

        // let editing = if model.mode == crate::types::Mode::Edit {
        let dropdown = if enabled && selected {
            html! {

                    { for entries }

            }
        } else {
            html! {}
        };
        let suffix = if enabled && selected {
            html! {
                { suffix }
            }
        } else {
            html! {}
        };
        let mut classes = if enabled && selected {
            match selected_entry {
                Some(entry) => entry.valid_classes.clone().join(" "),
                None => "".to_string(),
            }
        } else {
            "".to_string()
        };
        classes.push_str(" flex");

        let oninput = props.oninput.clone();
        let oninput = ctx.link().callback(move |e: InputEvent| {
            let v = get_value_from_input_event(e);
            oninput.emit(v.clone());
            CommandLineMsg::Input(v)
        });

        let onclick = ctx.link().callback(|_| CommandLineMsg::Click);
        let onfocus = ctx.link().callback(|_| CommandLineMsg::Click);
        let onkeydown = ctx
            .link()
            .callback(move |e: KeyboardEvent| CommandLineMsg::Key(e));

        html! {

                { for placeholder }

                        <textarea
                        rows={ format!("{}", rows) }
                        ref={ ctx.props().input_node_ref.clone() }
                        //   id={ id }
                        class={ class }
                        type="text"
                        oninput={ oninput }
                        onkeydown={ onkeydown }
                        //   onfocus={ onfocus }
                        value={ value.to_string() }
                        style={ style }
                        //   disabled={ model.mode != crate::types::Mode::Edit }
                        autocomplete="off"
                        >
                        </textarea>
                        { suffix }

                    { dropdown }

        }
    }

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            CommandLineMsg::Noop => false,
            CommandLineMsg::Click => {
                let input_node = ctx.props().input_node_ref.clone();
                input_node
                    .cast::<HtmlInputElement>()
                    .unwrap()
                    .focus()
                    .unwrap();
                true
            }
            CommandLineMsg::Input(value) => {
                self.value = value.clone();
                self.valid_entries = ctx
                    .props()
                    .entries
                    .clone()
                    .into_iter()
                    .filter(|v| v.label.starts_with(&value))
                    .collect();
                true
            }
            CommandLineMsg::Key(e) => {
                let props = ctx.props();
                let entries = &self.valid_entries;
                let selected_command_index = self.selected_command_index;
                if e.shift_key() {
                    return false;
                }
                match e.key().as_ref() {
                    "ArrowUp" => {
                        if entries.len() > 0 {
                            self.selected_command_index = if selected_command_index > 0 {
                                selected_command_index - 1
                            } else {
                                entries.len() - 1
                            }
                        }
                    }
                    "ArrowDown" => {
                        if entries.len() > 0 {
                            self.selected_command_index =
                                if selected_command_index < entries.len() - 1 {
                                    selected_command_index + 1
                                } else {
                                    0
                                }
                        }
                    }
                    "Enter" => {
                        e.prevent_default();
                        let selected_entry = entries.get(selected_command_index).cloned();
                        if let Some(selected_entry) = selected_entry {
                            let action = selected_entry.action.clone();
                            props.onselect.emit(action);
                        } else {
                            props.onenter.emit(());
                        }
                    }
                    _ => {}
                };
                true
            }
        }
    }
}
<|endoftext|>


<commit_before>use libc::c_char;
use std::ffi::{CString, CStr, NulError};

use GameControllerSubsystem;
use get_error;
use joystick;
use common::{validate_int, IntegerOrSdlError};

use sys::controller as ll;
use sys::event::{SDL_QUERY, SDL_ENABLE};

#[derive(Debug)]
pub enum AddMappingError {
    InvalidMapping(NulError),
    SdlError(String),
}

impl GameControllerSubsystem {
    /// Retreive the total number of attached joysticks *and* controllers identified by SDL.
    pub fn num_joysticks(&self) -> Result<u32, String> {
        let result = unsafe { ::sys::joystick::SDL_NumJoysticks() };

        if result >= 0 {
            Ok(result as u32)
        } else {
            Err(get_error())
        }
    }

    /// Return true if the joystick at index `id` is a game controller.
    #[inline]
    pub fn is_game_controller(&self, id: u32) -> bool {
        match validate_int(id, "id") {
            Ok(id) => unsafe { ll::SDL_IsGameController(id) != 0 },
            Err(_) => false
        }
    }

    /// Attempt to open the controller number `id` and return
    /// it. Controller IDs are the same as joystick IDs and the
    /// maximum number can be retreived using the `SDL_NumJoysticks`
    /// function.
    pub fn open(&self, id: u32) -> Result<GameController, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let id = try!(validate_int(id, "id"));
        let controller = unsafe { ll::SDL_GameControllerOpen(id) };

        if controller.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(GameController {
                subsystem: self.clone(),
                raw: controller
            })
        }
    }

    /// Return the name of the controller at the given index.
    pub fn name_for_index(&self, index: u32) -> Result<String, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let index = try!(validate_int(index, "index"));
        let c_str = unsafe { ll::SDL_GameControllerNameForIndex(index) };

        if c_str.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(unsafe {
                CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
            })
        }
    }

    /// If state is `true` controller events are processed, otherwise
    /// they're ignored.
    pub fn set_event_state(&self, state: bool) {
        unsafe { ll::SDL_GameControllerEventState(state as i32) };
    }

    /// Return `true` if controller events are processed.
    pub fn event_state(&self) -> bool {
        unsafe { ll::SDL_GameControllerEventState(SDL_QUERY as i32)
                 == SDL_ENABLE as i32 }
    }

    /// Add a new mapping from a mapping string
    pub fn add_mapping(&self, mapping: &str)
            -> Result<MappingStatus, AddMappingError> {
        use self::AddMappingError::*;
        let mapping = match CString::new(mapping) {
            Ok(s) => s,
            Err(err) => return Err(InvalidMapping(err)),
        };

        let result = unsafe { ll::SDL_GameControllerAddMapping(mapping.as_ptr() as *const c_char) };

        match result {
            1 => Ok(MappingStatus::Added),
            0 => Ok(MappingStatus::Updated),
            _ => Err(SdlError(get_error())),
        }
    }

    pub fn mapping_for_guid(&self, guid: joystick::Guid) -> Result<String, String> {
        let c_str = unsafe { ll::SDL_GameControllerMappingForGUID(guid.raw()) };

        c_str_to_string_or_err(c_str)
    }

    #[inline]
    /// Force controller update when not using the event loop
    pub fn update(&self) {
        unsafe { ll::SDL_GameControllerUpdate() };
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Axis {
    LeftX        = ll::SDL_CONTROLLER_AXIS_LEFTX,
    LeftY        = ll::SDL_CONTROLLER_AXIS_LEFTY,
    RightX       = ll::SDL_CONTROLLER_AXIS_RIGHTX,
    RightY       = ll::SDL_CONTROLLER_AXIS_RIGHTY,
    TriggerLeft  = ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
    TriggerRight = ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
}

impl Axis {
    /// Return the Axis from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(axis: &str) -> Option<Axis> {
        let id = match CString::new(axis) {
            Ok(axis) => unsafe { ll::SDL_GameControllerGetAxisFromString(axis.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_AXIS_INVALID
        };

        Axis::from_ll(id)
    }

    /// Return a string for a given axis in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let axis = self as ll::SDL_GameControllerAxis;

        let string = unsafe { ll::SDL_GameControllerGetStringForAxis(axis) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerAxis) -> Option<Axis> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_AXIS_INVALID      => return None,
            ll::SDL_CONTROLLER_AXIS_LEFTX        => Axis::LeftX,
            ll::SDL_CONTROLLER_AXIS_LEFTY        => Axis::LeftY,
            ll::SDL_CONTROLLER_AXIS_RIGHTX       => Axis::RightX,
            ll::SDL_CONTROLLER_AXIS_RIGHTY       => Axis::RightY,
            ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT  => Axis::TriggerLeft,
            ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => Axis::TriggerRight,
            _ => panic!("unhandled controller axis")
        })
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Button {
    A             = ll::SDL_CONTROLLER_BUTTON_A,
    B             = ll::SDL_CONTROLLER_BUTTON_B,
    X             = ll::SDL_CONTROLLER_BUTTON_X,
    Y             = ll::SDL_CONTROLLER_BUTTON_Y,
    Back          = ll::SDL_CONTROLLER_BUTTON_BACK,
    Guide         = ll::SDL_CONTROLLER_BUTTON_GUIDE,
    Start         = ll::SDL_CONTROLLER_BUTTON_START,
    LeftStick     = ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
    RightStick    = ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
    LeftShoulder  = ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
    RightShoulder = ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
    DPadUp        = ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
    DPadDown      = ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
    DPadLeft      = ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
    DPadRight     = ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
}

impl Button {
    /// Return the Button from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(button: &str) -> Option<Button> {
        let id = match CString::new(button) {
            Ok(button) => unsafe { ll::SDL_GameControllerGetButtonFromString(button.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_BUTTON_INVALID
        };

        Button::from_ll(id)
    }

    /// Return a string for a given button in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let button = self as ll::SDL_GameControllerButton;

        let string = unsafe { ll::SDL_GameControllerGetStringForButton(button) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerButton) -> Option<Button> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_BUTTON_INVALID       => return None,
            ll::SDL_CONTROLLER_BUTTON_A             => Button::A,
            ll::SDL_CONTROLLER_BUTTON_B             => Button::B,
            ll::SDL_CONTROLLER_BUTTON_X             => Button::X,
            ll::SDL_CONTROLLER_BUTTON_Y             => Button::Y,
            ll::SDL_CONTROLLER_BUTTON_BACK          => Button::Back,
            ll::SDL_CONTROLLER_BUTTON_GUIDE         => Button::Guide,
            ll::SDL_CONTROLLER_BUTTON_START         => Button::Start,
            ll::SDL_CONTROLLER_BUTTON_LEFTSTICK     => Button::LeftStick,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK    => Button::RightStick,
            ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER  => Button::LeftShoulder,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => Button::RightShoulder,
            ll::SDL_CONTROLLER_BUTTON_DPAD_UP       => Button::DPadUp,
            ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN     => Button::DPadDown,
            ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT     => Button::DPadLeft,
            ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT    => Button::DPadRight,
            _ => panic!("unhandled controller button")
        })
    }
}

/// Possible return values for `add_mapping`
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MappingStatus {
    Added   = 1,
    Updated = 0,
}

/// Wrapper around the SDL_GameController object
pub struct GameController {
    subsystem: GameControllerSubsystem,
    raw: *mut ll::SDL_GameController
}

impl GameController {
    #[inline]
    pub fn subsystem(&self) -> &GameControllerSubsystem { &self.subsystem }

    /// Return the name of the controller or an empty string if no
    /// name is found.
    pub fn name(&self) -> String {
        let name = unsafe { ll::SDL_GameControllerName(self.raw) };

        c_str_to_string(name)
    }

    /// Return a String describing the controller's button and axis
    /// mappings
    pub fn mapping(&self) -> String {
        let mapping = unsafe { ll::SDL_GameControllerMapping(self.raw) };

        c_str_to_string(mapping)
    }

    /// Return true if the controller has been opened and currently
    /// connected.
    pub fn attached(&self) -> bool {
        unsafe { ll::SDL_GameControllerGetAttached(self.raw) != 0 }
    }

    /// Get the position of the given `axis`
    pub fn axis(&self, axis: Axis) -> i16 {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let axis = axis as ll::SDL_GameControllerAxis;

        unsafe { ll::SDL_GameControllerGetAxis(self.raw, axis) }
    }

    /// Returns `true` if `button` is pressed.
    pub fn button(&self, button: Button) -> bool {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let button = button as ll::SDL_GameControllerButton;

        unsafe { ll::SDL_GameControllerGetButton(self.raw, button) != 0 }
    }
}

impl Drop for GameController {
    fn drop(&mut self) {
        unsafe { ll::SDL_GameControllerClose(self.raw) }
    }
}

/// Convert C string `c_str` to a String. Return an empty string if
/// c_str is NULL.
fn c_str_to_string(c_str: *const c_char) -> String {
    if c_str.is_null() {
        String::new()
    } else {
        unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        }
    }
}

/// Convert C string `c_str` to a String. Return an SDL error if
/// `c_str` is NULL.
fn c_str_to_string_or_err(c_str: *const c_char) -> Result<String, String> {
    if c_str.is_null() {
        Err(get_error())
    } else {
        Ok(unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        })
    }
}
<commit_msg>Added instance_id to GameController to get it's JoystickId<commit_after>use libc::c_char;
use std::ffi::{CString, CStr, NulError};

use GameControllerSubsystem;
use get_error;
use joystick;
use common::{validate_int, IntegerOrSdlError};

use sys::controller as ll;
use sys::event::{SDL_QUERY, SDL_ENABLE};

#[derive(Debug)]
pub enum AddMappingError {
    InvalidMapping(NulError),
    SdlError(String),
}

impl GameControllerSubsystem {
    /// Retreive the total number of attached joysticks *and* controllers identified by SDL.
    pub fn num_joysticks(&self) -> Result<u32, String> {
        let result = unsafe { ::sys::joystick::SDL_NumJoysticks() };

        if result >= 0 {
            Ok(result as u32)
        } else {
            Err(get_error())
        }
    }

    /// Return true if the joystick at index `id` is a game controller.
    #[inline]
    pub fn is_game_controller(&self, id: u32) -> bool {
        match validate_int(id, "id") {
            Ok(id) => unsafe { ll::SDL_IsGameController(id) != 0 },
            Err(_) => false
        }
    }

    /// Attempt to open the controller number `id` and return
    /// it. Controller IDs are the same as joystick IDs and the
    /// maximum number can be retreived using the `SDL_NumJoysticks`
    /// function.
    pub fn open(&self, id: u32) -> Result<GameController, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let id = try!(validate_int(id, "id"));
        let controller = unsafe { ll::SDL_GameControllerOpen(id) };

        if controller.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(GameController {
                subsystem: self.clone(),
                raw: controller
            })
        }
    }

    /// Return the name of the controller at the given index.
    pub fn name_for_index(&self, index: u32) -> Result<String, IntegerOrSdlError> {
        use common::IntegerOrSdlError::*;
        let index = try!(validate_int(index, "index"));
        let c_str = unsafe { ll::SDL_GameControllerNameForIndex(index) };

        if c_str.is_null() {
            Err(SdlError(get_error()))
        } else {
            Ok(unsafe {
                CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
            })
        }
    }

    /// If state is `true` controller events are processed, otherwise
    /// they're ignored.
    pub fn set_event_state(&self, state: bool) {
        unsafe { ll::SDL_GameControllerEventState(state as i32) };
    }

    /// Return `true` if controller events are processed.
    pub fn event_state(&self) -> bool {
        unsafe { ll::SDL_GameControllerEventState(SDL_QUERY as i32)
                 == SDL_ENABLE as i32 }
    }

    /// Add a new mapping from a mapping string
    pub fn add_mapping(&self, mapping: &str)
            -> Result<MappingStatus, AddMappingError> {
        use self::AddMappingError::*;
        let mapping = match CString::new(mapping) {
            Ok(s) => s,
            Err(err) => return Err(InvalidMapping(err)),
        };

        let result = unsafe { ll::SDL_GameControllerAddMapping(mapping.as_ptr() as *const c_char) };

        match result {
            1 => Ok(MappingStatus::Added),
            0 => Ok(MappingStatus::Updated),
            _ => Err(SdlError(get_error())),
        }
    }

    pub fn mapping_for_guid(&self, guid: joystick::Guid) -> Result<String, String> {
        let c_str = unsafe { ll::SDL_GameControllerMappingForGUID(guid.raw()) };

        c_str_to_string_or_err(c_str)
    }

    #[inline]
    /// Force controller update when not using the event loop
    pub fn update(&self) {
        unsafe { ll::SDL_GameControllerUpdate() };
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Axis {
    LeftX        = ll::SDL_CONTROLLER_AXIS_LEFTX,
    LeftY        = ll::SDL_CONTROLLER_AXIS_LEFTY,
    RightX       = ll::SDL_CONTROLLER_AXIS_RIGHTX,
    RightY       = ll::SDL_CONTROLLER_AXIS_RIGHTY,
    TriggerLeft  = ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT,
    TriggerRight = ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
}

impl Axis {
    /// Return the Axis from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(axis: &str) -> Option<Axis> {
        let id = match CString::new(axis) {
            Ok(axis) => unsafe { ll::SDL_GameControllerGetAxisFromString(axis.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_AXIS_INVALID
        };

        Axis::from_ll(id)
    }

    /// Return a string for a given axis in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let axis = self as ll::SDL_GameControllerAxis;

        let string = unsafe { ll::SDL_GameControllerGetStringForAxis(axis) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerAxis) -> Option<Axis> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_AXIS_INVALID      => return None,
            ll::SDL_CONTROLLER_AXIS_LEFTX        => Axis::LeftX,
            ll::SDL_CONTROLLER_AXIS_LEFTY        => Axis::LeftY,
            ll::SDL_CONTROLLER_AXIS_RIGHTX       => Axis::RightX,
            ll::SDL_CONTROLLER_AXIS_RIGHTY       => Axis::RightY,
            ll::SDL_CONTROLLER_AXIS_TRIGGERLEFT  => Axis::TriggerLeft,
            ll::SDL_CONTROLLER_AXIS_TRIGGERRIGHT => Axis::TriggerRight,
            _ => panic!("unhandled controller axis")
        })
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum Button {
    A             = ll::SDL_CONTROLLER_BUTTON_A,
    B             = ll::SDL_CONTROLLER_BUTTON_B,
    X             = ll::SDL_CONTROLLER_BUTTON_X,
    Y             = ll::SDL_CONTROLLER_BUTTON_Y,
    Back          = ll::SDL_CONTROLLER_BUTTON_BACK,
    Guide         = ll::SDL_CONTROLLER_BUTTON_GUIDE,
    Start         = ll::SDL_CONTROLLER_BUTTON_START,
    LeftStick     = ll::SDL_CONTROLLER_BUTTON_LEFTSTICK,
    RightStick    = ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
    LeftShoulder  = ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
    RightShoulder = ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
    DPadUp        = ll::SDL_CONTROLLER_BUTTON_DPAD_UP,
    DPadDown      = ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
    DPadLeft      = ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
    DPadRight     = ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
}

impl Button {
    /// Return the Button from a string description in the same format
    /// used by the game controller mapping strings.
    pub fn from_string(button: &str) -> Option<Button> {
        let id = match CString::new(button) {
            Ok(button) => unsafe { ll::SDL_GameControllerGetButtonFromString(button.as_ptr() as *const c_char) },
            // string contains a nul byte - it won't match anything.
            Err(_) => ll::SDL_CONTROLLER_BUTTON_INVALID
        };

        Button::from_ll(id)
    }

    /// Return a string for a given button in the same format using by
    /// the game controller mapping strings
    pub fn string(self) -> String {
        let button = self as ll::SDL_GameControllerButton;

        let string = unsafe { ll::SDL_GameControllerGetStringForButton(button) };

        c_str_to_string(string)
    }

    pub fn from_ll(bitflags: ll::SDL_GameControllerButton) -> Option<Button> {
        Some(match bitflags {
            ll::SDL_CONTROLLER_BUTTON_INVALID       => return None,
            ll::SDL_CONTROLLER_BUTTON_A             => Button::A,
            ll::SDL_CONTROLLER_BUTTON_B             => Button::B,
            ll::SDL_CONTROLLER_BUTTON_X             => Button::X,
            ll::SDL_CONTROLLER_BUTTON_Y             => Button::Y,
            ll::SDL_CONTROLLER_BUTTON_BACK          => Button::Back,
            ll::SDL_CONTROLLER_BUTTON_GUIDE         => Button::Guide,
            ll::SDL_CONTROLLER_BUTTON_START         => Button::Start,
            ll::SDL_CONTROLLER_BUTTON_LEFTSTICK     => Button::LeftStick,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSTICK    => Button::RightStick,
            ll::SDL_CONTROLLER_BUTTON_LEFTSHOULDER  => Button::LeftShoulder,
            ll::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => Button::RightShoulder,
            ll::SDL_CONTROLLER_BUTTON_DPAD_UP       => Button::DPadUp,
            ll::SDL_CONTROLLER_BUTTON_DPAD_DOWN     => Button::DPadDown,
            ll::SDL_CONTROLLER_BUTTON_DPAD_LEFT     => Button::DPadLeft,
            ll::SDL_CONTROLLER_BUTTON_DPAD_RIGHT    => Button::DPadRight,
            _ => panic!("unhandled controller button")
        })
    }
}

/// Possible return values for `add_mapping`
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MappingStatus {
    Added   = 1,
    Updated = 0,
}

/// Wrapper around the SDL_GameController object
pub struct GameController {
    subsystem: GameControllerSubsystem,
    raw: *mut ll::SDL_GameController
}

impl GameController {
    #[inline]
    pub fn subsystem(&self) -> &GameControllerSubsystem { &self.subsystem }

    /// Return the name of the controller or an empty string if no
    /// name is found.
    pub fn name(&self) -> String {
        let name = unsafe { ll::SDL_GameControllerName(self.raw) };

        c_str_to_string(name)
    }

    /// Return a String describing the controller's button and axis
    /// mappings
    pub fn mapping(&self) -> String {
        let mapping = unsafe { ll::SDL_GameControllerMapping(self.raw) };

        c_str_to_string(mapping)
    }

    /// Return true if the controller has been opened and currently
    /// connected.
    pub fn attached(&self) -> bool {
        unsafe { ll::SDL_GameControllerGetAttached(self.raw) != 0 }
    }

    /// Return the joystick id of this controller
    pub fn instance_id(&self) -> i32 {
        let result = unsafe {
          let joystick = ll::SDL_GameControllerGetJoystick(self.raw);
          ::sys::joystick::SDL_JoystickInstanceID(joystick)
        };

        if result < 0 {
            // Should only fail if the joystick is NULL.
            panic!(get_error())
        } else {
            result
        }
    }

    /// Get the position of the given `axis`
    pub fn axis(&self, axis: Axis) -> i16 {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let axis = axis as ll::SDL_GameControllerAxis;

        unsafe { ll::SDL_GameControllerGetAxis(self.raw, axis) }
    }

    /// Returns `true` if `button` is pressed.
    pub fn button(&self, button: Button) -> bool {
        // This interface is a bit messed up: 0 is a valid position
        // but can also mean that an error occured.
        // Fortunately, an error can only occur if the controller pointer is NULL.
        // There should be no apparent reason for this to change in the future.

        let button = button as ll::SDL_GameControllerButton;

        unsafe { ll::SDL_GameControllerGetButton(self.raw, button) != 0 }
    }
}

impl Drop for GameController {
    fn drop(&mut self) {
        unsafe { ll::SDL_GameControllerClose(self.raw) }
    }
}

/// Convert C string `c_str` to a String. Return an empty string if
/// c_str is NULL.
fn c_str_to_string(c_str: *const c_char) -> String {
    if c_str.is_null() {
        String::new()
    } else {
        unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        }
    }
}

/// Convert C string `c_str` to a String. Return an SDL error if
/// `c_str` is NULL.
fn c_str_to_string_or_err(c_str: *const c_char) -> Result<String, String> {
    if c_str.is_null() {
        Err(get_error())
    } else {
        Ok(unsafe {
            CStr::from_ptr(c_str as *const _).to_str().unwrap().to_owned()
        })
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate serde_json;

use std::collections::BTreeMap;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::sync::{ Mutex, RwLock };

type ConfigNameSpace = BTreeMap<String, String>;

type ConfigTree = BTreeMap<String, ConfigNameSpace>;

#[derive(Debug)]
pub struct ConfigStore {
    file_name: String,
    save_lock: Mutex<()>,
    config: ConfigTree
}

impl ConfigStore {
    pub fn new(file_name: &str) -> Self {
        ConfigStore {
            file_name: file_name.to_owned(),
            save_lock: Mutex::new(()),
            config: ConfigStore::load(file_name)
        }
    }

    pub fn set(&mut self, namespace: &str, property: &str, value: &str) {
        debug!("Setting config for {}::{} to {}", namespace, property, value);
        if !self.config.contains_key(namespace) {
            self.config.insert(namespace.to_owned(), ConfigNameSpace::new());
        }
        self.config.get_mut(namespace).unwrap().insert(property.to_owned(), value.to_owned());
        // TODO: Should be more intelligent than save on every write
        self.save();
    }

    pub fn get(&self, namespace: &str, property: &str) -> Option<&String> {
        if self.config.contains_key(namespace) {
            let res = self.config.get(namespace).unwrap().get(property);
            debug!("Config result for {}::{} is {:?}", namespace, property, res);
            res
        } else {
            debug!("No config result for {}::{}", namespace, property);
            None
        }
    }

    fn load(file_name: &str) -> ConfigTree {
        let empty_config = BTreeMap::new();
        let file = match File::open(&Path::new(file_name)) {
            Ok(file) => {
                file
            },
            Err(error) => {
                error!("Unable to open configuration file {}: {}",
                    file_name, error.to_string());
                return empty_config;
            }
        };
        let parsed_config: ConfigTree = match serde_json::from_reader(&file) {
            Ok(value) => value,
            Err(error) => {
                error!("Unable to generate JSON from config file {}: {}",
                    file_name, error.to_string());
                    empty_config
            }
        };

        debug!("Parsed config file: {:?}", parsed_config);
        parsed_config
    }

    fn save(&self) {
        let file_path = Path::new(&self.file_name);
        let mut update_name = self.file_name.clone();
        update_name.push_str(".updated");
        let update_path = Path::new(&update_name);

        let conf_as_json = serde_json::to_string_pretty(&self.config).unwrap();

        let _ = self.save_lock.lock().unwrap();
        match File::create(update_path)
            .map(|mut file| file.write_all(&conf_as_json.as_bytes()))
            .and_then(|_| { fs::copy(&update_path, &file_path) })
            .and_then(|_| { fs::remove_file(&update_path) }) {
                Ok(_) => debug!("Wrote configuration file {}", self.file_name),
                Err(error) => error!("While writing configuration file{}: {}",
                    self.file_name, error.to_string())
            };
    }
}

pub struct ConfigService {
    store: RwLock<ConfigStore>
}

impl ConfigService {
    pub fn new(file_name: &str) -> Self {
        ConfigService {
            store: RwLock::new(ConfigStore::new(file_name))
        }
    }

    pub fn get(&self, namespace: &str, property: &str) -> Option<String> {
        self.store.read().unwrap().get(namespace, property)
            .map(|value| { value.to_owned() })
    }

    pub fn get_or_set_default(&mut self, namespace: &str, property: &str, default: &str) -> String {
        self.get(namespace, property).unwrap_or_else(|| {
            self.set(namespace, property, default);
            default.to_owned()
        })
    }

    pub fn set(&mut self, namespace: &str, property: &str, value: &str) {
        self.store.write().unwrap().set(namespace, property, value);
    }
}

#[cfg(test)]
describe! config_store {

    before_each {
        use uuid::Uuid;
        use std::fs;
        let config_file_name = format!("conftest-{}.tmp", Uuid::new_v4().to_simple_string());
    }

    it "should remember properties" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigStore::new(&config_file_name);
            config.set("foo", "bar", "baz");
            assert_eq!(
                config.get("foo", "bar"),
                Some(&"baz".to_string())
            );
        }
        // Would use after_each, but after_each is never called:
        fs::remove_file(config_file_name).unwrap_or(());
    }

    it "should return None on non-existent namespaces" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigStore::new(&config_file_name);
            config.set("foo", "bar", "baz");
            assert_eq!(
                config.get("foofoo", "bar"),
                None
            );
        }
        fs::remove_file(config_file_name).unwrap_or(());
    }

    it "should return None on non-existent properties" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigStore::new(&config_file_name);
            config.set("foo", "bar", "baz");
            assert_eq!(
                config.get("foo", "barbar"),
                None
            );
        }
        fs::remove_file(config_file_name).unwrap_or(());
    }

    it "should remember things over restarts" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigStore::new(&config_file_name);
            config.set("foo", "bar", "baz");
        }
        // `config` should now be out of scope and dropped
        {
            let config = ConfigStore::new(&config_file_name);
            assert_eq!(
                config.get("foo", "bar"),
                Some(&"baz".to_string())
            );
        }
        fs::remove_file(config_file_name).unwrap_or(());
    }
}

#[cfg(test)]
describe! config_service {

    before_each {
        use uuid::Uuid;
        use std::fs;
        let config_file_name = format!("conftest-{}.tmp", Uuid::new_v4().to_simple_string());
    }

    it "should remember properties" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigService::new(&config_file_name);
            config.set("foo", "bar", "baz");
            assert_eq!(
                config.get("foo", "bar"),
                Some("baz".to_string())
            );
        }
        // Would use after_each, but after_each is never called:
        fs::remove_file(config_file_name).unwrap_or(());
    }

    it "should return the default value when needed" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigService::new(&config_file_name);
            let res = config.get_or_set_default("foo", "bar", "default");
            assert_eq!(res, "default");

            // It is now set.
            assert_eq!(
                config.get("foo", "bar"),
                Some("default".to_string())
            );
        }
        fs::remove_file(config_file_name).unwrap_or(());
    }

    it "should return None on non-existent namespaces" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigService::new(&config_file_name);
            config.set("foo", "bar", "baz");
            assert_eq!(
                config.get("foofoo", "bar"),
                None
            );
        }
        fs::remove_file(config_file_name).unwrap_or(());
    }

    it "should return None on non-existent properties" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigService::new(&config_file_name);
            config.set("foo", "bar", "baz");
            assert_eq!(
                config.get("foo", "barbar"),
                None
            );
        }
        fs::remove_file(config_file_name).unwrap_or(());
    }

    it "should remember things over restarts" {
        // Block to make `config` go out of scope
        {
            let mut config = ConfigService::new(&config_file_name);
            config.set("foo", "bar", "baz");
        }
        // `config` should now be out of scope and dropped
        {
            let config = ConfigService::new(&config_file_name);
            assert_eq!(
                config.get("foo", "bar"),
                Some("baz".to_string())
            );
        }
        fs::remove_file(config_file_name).unwrap_or(());
    }
}
<commit_msg>config_store: Add after_each{}<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate serde_json;

use std::collections::BTreeMap;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::sync::{ Mutex, RwLock };

type ConfigNameSpace = BTreeMap<String, String>;

type ConfigTree = BTreeMap<String, ConfigNameSpace>;

#[derive(Debug)]
pub struct ConfigStore {
    file_name: String,
    save_lock: Mutex<()>,
    config: ConfigTree
}

impl ConfigStore {
    pub fn new(file_name: &str) -> Self {
        ConfigStore {
            file_name: file_name.to_owned(),
            save_lock: Mutex::new(()),
            config: ConfigStore::load(file_name)
        }
    }

    pub fn set(&mut self, namespace: &str, property: &str, value: &str) {
        debug!("Setting config for {}::{} to {}", namespace, property, value);
        if !self.config.contains_key(namespace) {
            self.config.insert(namespace.to_owned(), ConfigNameSpace::new());
        }
        self.config.get_mut(namespace).unwrap().insert(property.to_owned(), value.to_owned());
        // TODO: Should be more intelligent than save on every write
        self.save();
    }

    pub fn get(&self, namespace: &str, property: &str) -> Option<&String> {
        if self.config.contains_key(namespace) {
            let res = self.config.get(namespace).unwrap().get(property);
            debug!("Config result for {}::{} is {:?}", namespace, property, res);
            res
        } else {
            debug!("No config result for {}::{}", namespace, property);
            None
        }
    }

    fn load(file_name: &str) -> ConfigTree {
        let empty_config = BTreeMap::new();
        let file = match File::open(&Path::new(file_name)) {
            Ok(file) => {
                file
            },
            Err(error) => {
                error!("Unable to open configuration file {}: {}",
                    file_name, error.to_string());
                return empty_config;
            }
        };
        let parsed_config: ConfigTree = match serde_json::from_reader(&file) {
            Ok(value) => value,
            Err(error) => {
                error!("Unable to generate JSON from config file {}: {}",
                    file_name, error.to_string());
                    empty_config
            }
        };

        debug!("Parsed config file: {:?}", parsed_config);
        parsed_config
    }

    fn save(&self) {
        let file_path = Path::new(&self.file_name);
        let mut update_name = self.file_name.clone();
        update_name.push_str(".updated");
        let update_path = Path::new(&update_name);

        let conf_as_json = serde_json::to_string_pretty(&self.config).unwrap();

        let _ = self.save_lock.lock().unwrap();
        match File::create(update_path)
            .map(|mut file| file.write_all(&conf_as_json.as_bytes()))
            .and_then(|_| { fs::copy(&update_path, &file_path) })
            .and_then(|_| { fs::remove_file(&update_path) }) {
                Ok(_) => debug!("Wrote configuration file {}", self.file_name),
                Err(error) => error!("While writing configuration file{}: {}",
                    self.file_name, error.to_string())
            };
    }
}

pub struct ConfigService {
    store: RwLock<ConfigStore>
}

impl ConfigService {
    pub fn new(file_name: &str) -> Self {
        ConfigService {
            store: RwLock::new(ConfigStore::new(file_name))
        }
    }

    pub fn get(&self, namespace: &str, property: &str) -> Option<String> {
        self.store.read().unwrap().get(namespace, property)
            .map(|value| { value.to_owned() })
    }

    pub fn get_or_set_default(&mut self, namespace: &str, property: &str, default: &str) -> String {
        self.get(namespace, property).unwrap_or_else(|| {
            self.set(namespace, property, default);
            default.to_owned()
        })
    }

    pub fn set(&mut self, namespace: &str, property: &str, value: &str) {
        self.store.write().unwrap().set(namespace, property, value);
    }
}

#[cfg(test)]
describe! config {

    before_each {
        use uuid::Uuid;
        use std::fs;
        let config_file_name = format!("conftest-{}.tmp", Uuid::new_v4().to_simple_string());
    }

    after_each {
        fs::remove_file(config_file_name).unwrap_or(());
    }

    describe! config_store {
        before_each {
            let mut config = ConfigStore::new(&config_file_name);
        }

        it "should remember properties" {
            config.set("foo", "bar", "baz");
            let foo_bar = config.get("foo", "bar").unwrap();
            assert_eq!(foo_bar, "baz");
        }

        it "should return None on non-existent namespaces" {
            config.set("foo", "bar", "baz");
            assert_eq!(config.get("foofoo", "bar"), None);
        }

        it "should return None on non-existent properties" {
            config.set("foo", "bar", "baz");
            assert_eq!(config.get("foo", "barbar"), None);
        }
    }

    describe! config_service {
        before_each {
            let mut config = ConfigService::new(&config_file_name);
        }

        it "should remember properties" {
            config.set("foo", "bar", "baz");
            let foo_bar = config.get("foo", "bar").unwrap();
            assert_eq!(foo_bar, "baz");
        }

        it "should return the default value when needed" {
            let res = config.get_or_set_default("foo", "bar", "default");
            assert_eq!(res, "default");

            let foo_bar = config.get("foo", "bar").unwrap();
            assert_eq!(foo_bar, "default");
        }

        it "should return None on non-existent namespaces" {
            config.set("foo", "bar", "baz");
            assert_eq!(config.get("foofoo", "bar"), None);
        }

        it "should return None on non-existent properties" {
            config.set("foo", "bar", "baz");
            assert_eq!(config.get("foo", "barbar"), None);
        }
    }

    describe! restarts {
        it "ConfigStore should remember things over restarts" {
            // Block to make `config` go out of scope
            {
                let mut config = ConfigStore::new(&config_file_name);
                config.set("foo", "bar", "baz");
            }
            // `config` should now be out of scope and dropped
            {
                let config = ConfigStore::new(&config_file_name);
                let foo_bar = config.get("foo", "bar").unwrap();
                assert_eq!(foo_bar, "baz");
            };
        }

        it "ConfigService should remember things over restarts" {
            // Block to make `config` go out of scope
            {
                let mut config = ConfigService::new(&config_file_name);
                config.set("foo", "bar", "baz");
            }
            // `config` should now be out of scope and dropped
            {
                let config = ConfigService::new(&config_file_name);
                let foo_bar = config.get("foo", "bar").unwrap();
                assert_eq!(foo_bar, "baz");
            };
        }
    }
}
<|endoftext|>