<commit_before>use super::*;

fn build_app() -> App<'static> {
    build_app_with_name("myapp")
}

fn build_app_with_name(s: &'static str) -> App<'static> {
    App::new(s)
        .version("3.0")
        .setting(AppSettings::PropagateVersion)
        .about("Tests completions")
        .arg(
            Arg::new("file")
                .value_hint(ValueHint::FilePath)
                .help("some input file"),
        )
        .arg(
            Arg::new("config")
                .help("some config file")
                .short('c')
                .visible_short_alias('C')
                .long("config")
                .visible_alias("conf"),
        )
        .subcommand(
            App::new("test").about("tests things").arg(
                Arg::new("case")
                    .long("case")
                    .takes_value(true)
                    .help("the case to test"),
            ),
        )
}

#[test]
fn powershell() {
    let mut app = build_app();
    common(PowerShell, &mut app, "my_app", POWERSHELL);
}

static POWERSHELL: &str = r#"
using namespace System.Management.Automation
using namespace System.Management.Automation.Language

Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commandElements = $commandAst.CommandElements
    $command = @(
        'my_app'
        for ($i = 1; $i -lt $commandElements.Count; $i++) {
            $element = $commandElements[$i]
            if ($element -isnot [StringConstantExpressionAst] -or
                $element.StringConstantType -ne [StringConstantType]::BareWord -or
                $element.Value.StartsWith('-')) {
                break
        }
        $element.Value
    }) -join ';'

    $completions = @(switch ($command) {
        'my_app' {
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('-C', 'C', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--conf', 'conf', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things')
            [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
            break
        }
        'my_app;test' {
            [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;help' {
            break
        }
    })

    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
        Sort-Object -Property ListItemText
}
"#;

#[test]
fn powershell_with_special_commands() {
    let mut app = build_app_special_commands();
    common(PowerShell, &mut app, "my_app", POWERSHELL_SPECIAL_CMDS);
}

fn build_app_special_commands() -> App<'static> {
    build_app_with_name("my_app")
        .subcommand(
            App::new("some_cmd").about("tests other things").arg(
                Arg::new("config")
                    .long("--config")
                    .takes_value(true)
                    .help("the other case to test"),
            ),
        )
        .subcommand(App::new("some-cmd-with-hyphens").alias("hyphen"))
}

static POWERSHELL_SPECIAL_CMDS: &str = r#"
using namespace System.Management.Automation
using namespace System.Management.Automation.Language

Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commandElements = $commandAst.CommandElements
    $command = @(
        'my_app'
        for ($i = 1; $i -lt $commandElements.Count; $i++) {
            $element = $commandElements[$i]
            if ($element -isnot [StringConstantExpressionAst] -or
                $element.StringConstantType -ne [StringConstantType]::BareWord -or
                $element.Value.StartsWith('-')) {
                break
        }
        $element.Value
    }) -join ';'

    $completions = @(switch ($command) {
        'my_app' {
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('-C', 'C', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--conf', 'conf', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things')
            [CompletionResult]::new('some_cmd', 'some_cmd', [CompletionResultType]::ParameterValue, 'tests other things')
            [CompletionResult]::new('some-cmd-with-hyphens', 'some-cmd-with-hyphens', [CompletionResultType]::ParameterValue, 'some-cmd-with-hyphens')
            [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
            break
        }
        'my_app;test' {
            [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;some_cmd' {
            [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'the other case to test')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;some-cmd-with-hyphens' {
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;help' {
            break
        }
    })

    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
        Sort-Object -Property ListItemText
}
"#;

#[test]
fn powershell_with_aliases() {
    let mut app = build_app_with_aliases();
    common(PowerShell, &mut app, "cmd", POWERSHELL_ALIASES);
}

fn build_app_with_aliases() -> App<'static> {
    App::new("cmd")
        .version("3.0")
        .about("testing bash completions")
        .arg(
            Arg::new("flag")
                .short('f')
                .visible_short_alias('F')
                .long("flag")
                .visible_alias("flg")
                .help("cmd flag"),
        )
        .arg(
            Arg::new("option")
                .short('o')
                .visible_short_alias('O')
                .long("option")
                .visible_alias("opt")
                .help("cmd option")
                .takes_value(true),
        )
        .arg(Arg::new("positional"))
}

static POWERSHELL_ALIASES: &str = r#"
using namespace System.Management.Automation
using namespace System.Management.Automation.Language

Register-ArgumentCompleter -Native -CommandName 'cmd' -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commandElements = $commandAst.CommandElements
    $command = @(
        'cmd'
        for ($i = 1; $i -lt $commandElements.Count; $i++) {
            $element = $commandElements[$i]
            if ($element -isnot [StringConstantExpressionAst] -or
                $element.StringConstantType -ne [StringConstantType]::BareWord -or
                $element.Value.StartsWith('-')) {
                break
        }
        $element.Value
    }) -join ';'

    $completions = @(switch ($command) {
        'cmd' {
            [CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('-O', 'O', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('--option', 'option', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('--opt', 'opt', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'cmd flag')
            [CompletionResult]::new('-F', 'F', [CompletionResultType]::ParameterName, 'cmd flag')
            [CompletionResult]::new('--flag', 'flag', [CompletionResultType]::ParameterName, 'cmd flag')
            [CompletionResult]::new('--flg', 'flg', [CompletionResultType]::ParameterName, 'cmd flag')
            break
        }
    })

    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
        Sort-Object -Property ListItemText
}
"#;
<commit_msg>Fixed failing test<commit_after>use super::*;

fn build_app() -> App<'static> {
    build_app_with_name("myapp")
}

fn build_app_with_name(s: &'static str) -> App<'static> {
    App::new(s)
        .version("3.0")
        .setting(AppSettings::PropagateVersion)
        .about("Tests completions")
        .arg(
            Arg::new("file")
                .value_hint(ValueHint::FilePath)
                .help("some input file"),
        )
        .arg(
            Arg::new("config")
                .help("some config file")
                .short('c')
                .visible_short_alias('C')
                .long("config")
                .visible_alias("conf"),
        )
        .subcommand(
            App::new("test").about("tests things").arg(
                Arg::new("case")
                    .long("case")
                    .takes_value(true)
                    .help("the case to test"),
            ),
        )
}

#[test]
fn powershell() {
    let mut app = build_app();
    common(PowerShell, &mut app, "my_app", POWERSHELL);
}

static POWERSHELL: &str = r#"
using namespace System.Management.Automation
using namespace System.Management.Automation.Language

Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commandElements = $commandAst.CommandElements
    $command = @(
        'my_app'
        for ($i = 1; $i -lt $commandElements.Count; $i++) {
            $element = $commandElements[$i]
            if ($element -isnot [StringConstantExpressionAst] -or
                $element.StringConstantType -ne [StringConstantType]::BareWord -or
                $element.Value.StartsWith('-')) {
                break
        }
        $element.Value
    }) -join ';'

    $completions = @(switch ($command) {
        'my_app' {
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('-C', 'C', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--conf', 'conf', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things')
            [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
            break
        }
        'my_app;test' {
            [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;help' {
            break
        }
    })

    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
        Sort-Object -Property ListItemText
}
"#;

#[test]
fn powershell_with_special_commands() {
    let mut app = build_app_special_commands();
    common(PowerShell, &mut app, "my_app", POWERSHELL_SPECIAL_CMDS);
}

fn build_app_special_commands() -> App<'static> {
    build_app_with_name("my_app")
        .subcommand(
            App::new("some_cmd").about("tests other things").arg(
                Arg::new("config")
                    .long("--config")
                    .takes_value(true)
                    .help("the other case to test"),
            ),
        )
        .subcommand(App::new("some-cmd-with-hyphens").alias("hyphen"))
}

static POWERSHELL_SPECIAL_CMDS: &str = r#"
using namespace System.Management.Automation
using namespace System.Management.Automation.Language

Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commandElements = $commandAst.CommandElements
    $command = @(
        'my_app'
        for ($i = 1; $i -lt $commandElements.Count; $i++) {
            $element = $commandElements[$i]
            if ($element -isnot [StringConstantExpressionAst] -or
                $element.StringConstantType -ne [StringConstantType]::BareWord -or
                $element.Value.StartsWith('-') -or
                $element.Value -eq $wordToComplete) {
                break
        }
        $element.Value
    }) -join ';'

    $completions = @(switch ($command) {
        'my_app' {
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('-C', 'C', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('--conf', 'conf', [CompletionResultType]::ParameterName, 'some config file')
            [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things')
            [CompletionResult]::new('some_cmd', 'some_cmd', [CompletionResultType]::ParameterValue, 'tests other things')
            [CompletionResult]::new('some-cmd-with-hyphens', 'some-cmd-with-hyphens', [CompletionResultType]::ParameterValue, 'some-cmd-with-hyphens')
            [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
            break
        }
        'my_app;test' {
            [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;some_cmd' {
            [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'the other case to test')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;some-cmd-with-hyphens' {
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            break
        }
        'my_app;help' {
            break
        }
    })

    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
        Sort-Object -Property ListItemText
}
"#;

#[test]
fn powershell_with_aliases() {
    let mut app = build_app_with_aliases();
    common(PowerShell, &mut app, "cmd", POWERSHELL_ALIASES);
}

fn build_app_with_aliases() -> App<'static> {
    App::new("cmd")
        .version("3.0")
        .about("testing bash completions")
        .arg(
            Arg::new("flag")
                .short('f')
                .visible_short_alias('F')
                .long("flag")
                .visible_alias("flg")
                .help("cmd flag"),
        )
        .arg(
            Arg::new("option")
                .short('o')
                .visible_short_alias('O')
                .long("option")
                .visible_alias("opt")
                .help("cmd option")
                .takes_value(true),
        )
        .arg(Arg::new("positional"))
}

static POWERSHELL_ALIASES: &str = r#"
using namespace System.Management.Automation
using namespace System.Management.Automation.Language

Register-ArgumentCompleter -Native -CommandName 'cmd' -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commandElements = $commandAst.CommandElements
    $command = @(
        'cmd'
        for ($i = 1; $i -lt $commandElements.Count; $i++) {
            $element = $commandElements[$i]
            if ($element -isnot [StringConstantExpressionAst] -or
                $element.StringConstantType -ne [StringConstantType]::BareWord -or
                $element.Value.StartsWith('-')) {
                break
        }
        $element.Value
    }) -join ';'

    $completions = @(switch ($command) {
        'cmd' {
            [CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('-O', 'O', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('--option', 'option', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('--opt', 'opt', [CompletionResultType]::ParameterName, 'cmd option')
            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information')
            [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information')
            [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'cmd flag')
            [CompletionResult]::new('-F', 'F', [CompletionResultType]::ParameterName, 'cmd flag')
            [CompletionResult]::new('--flag', 'flag', [CompletionResultType]::ParameterName, 'cmd flag')
            [CompletionResult]::new('--flg', 'flg', [CompletionResultType]::ParameterName, 'cmd flag')
            break
        }
    })

    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
        Sort-Object -Property ListItemText
}
"#;
<|endoftext|>


<commit_before>use types::Boolean;

use bit_vec::BitVec;

pub struct AMQPFlags {
    bv:    BitVec,
    index: i8,
}

impl AMQPFlags {
    pub fn new() -> AMQPFlags {
        AMQPFlags {
            bv: BitVec::from_elem(8, false),
            index: 7,
        }
    }

    pub fn add_flag(&mut self, f: Boolean) {
        /* TODO: handle multibyte flags */
        assert!(self.index >= 0);
        self.bv.set(self.index as usize, f);
        self.index -= 1;
    }

    pub fn get_bytes(&self) -> Vec<u8> {
        self.bv.to_bytes()
    }
}

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

    #[test]
    fn test_empty_flags() {
        assert_eq!(AMQPFlags::new().get_bytes().as_slice(), &[0])
    }

    #[test]
    fn test_flags() {
        let mut flags = AMQPFlags::new();
        flags.add_flag(true);
        flags.add_flag(false);
        flags.add_flag(false);
        flags.add_flag(true);
        flags.add_flag(true);
        assert_eq!(flags.get_bytes().as_slice(), &[0b00011001])
    }

    #[test]
    #[should_panic]
    fn test_many_flags() {
        let mut flags = AMQPFlags::new();
        for _ in 0..9 {
            flags.add_flag(false);
        }
    }
}
<commit_msg>types: support multibyte flags<commit_after>use types::Boolean;

use bit_vec::BitVec;

pub struct AMQPFlags {
    bv:    BitVec,
    index: i8,
    nbyte: u8,
}

impl AMQPFlags {
    pub fn new() -> AMQPFlags {
        AMQPFlags {
            bv: BitVec::from_elem(8, false),
            index: 7,
            nbyte: 0,
        }
    }

    fn next_byte(&mut self) {
        self.bv.grow(8, false);
        self.nbyte += 1;
        self.index = 7;
    }

    pub fn add_flag(&mut self, f: Boolean) {
        if self.index < 0 {
            self.next_byte();
        }
        self.bv.set((self.nbyte * 8 + (self.index as u8)) as usize, f);
        self.index -= 1;
    }

    pub fn get_bytes(&self) -> Vec<u8> {
        self.bv.to_bytes()
    }
}

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

    #[test]
    fn test_empty_flags() {
        assert_eq!(AMQPFlags::new().get_bytes().as_slice(), &[0])
    }

    #[test]
    fn test_flags() {
        let mut flags = AMQPFlags::new();
        flags.add_flag(true);
        flags.add_flag(false);
        flags.add_flag(false);
        flags.add_flag(true);
        flags.add_flag(true);
        assert_eq!(flags.get_bytes().as_slice(), &[0b00011001])
    }

    #[test]
    fn test_many_flags() {
        let mut flags = AMQPFlags::new();
        flags.add_flag(true);
        flags.add_flag(false);
        flags.add_flag(false);
        flags.add_flag(true);
        flags.add_flag(true);
        flags.add_flag(true);
        flags.add_flag(false);
        flags.add_flag(false);
        flags.add_flag(true);
        flags.add_flag(true);
        assert_eq!(flags.get_bytes().as_slice(), &[0b00111001, 0b00000011])
    }
}
<|endoftext|>


<commit_before>use value::AMQPValue;

use std::collections::BTreeMap;
use std::fmt;

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPType {
    Boolean,
    ShortShortInt,
    ShortShortUInt,
    ShortInt,
    ShortUInt,
    LongInt,
    LongUInt,
    LongLongInt,
    LongLongUInt,
    Float,
    Double,
    DecimalValue,
    ShortString,
    LongString,
    FieldArray,
    Timestamp,
    FieldTable,
    ByteArray, /* ByteArray is specific to RabbitMQ */
    Void,
}

impl AMQPType {
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    pub fn get_id(&self) -> char {
        match *self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }

    pub fn to_string(&self) -> String {
        format!("{}", self)
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

pub type Boolean        = bool;
pub type ShortShortInt  = i8;
pub type ShortShortUInt = u8;
pub type ShortInt       = i16;
pub type ShortUInt      = u16;
pub type LongInt        = i32;
pub type LongUInt       = u32;
pub type LongLongInt    = i64;
pub type LongLongUInt   = u64;
pub type Float          = f32;
pub type Double         = f64;
pub type ShortString    = String;
pub type LongString     = String;
pub type FieldArray     = Vec<AMQPValue>;
pub type Timestamp      = LongLongUInt;
pub type FieldTable     = BTreeMap<ShortString, AMQPValue>;
pub type ByteArray      = Vec<u8>;
pub type Void           = ();

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct DecimalValue {
    pub scale: ShortShortUInt,
    pub value: LongUInt,
}

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

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<commit_msg>types: document types<commit_after>use value::AMQPValue;

use std::collections::BTreeMap;
use std::fmt;

///! Enumeration referencing all the available AMQP types
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPType {
    ///! A bool
    Boolean,
    ///! An i8
    ShortShortInt,
    ///! A u8
    ShortShortUInt,
    ///! An i16
    ShortInt,
    ///! A u16
    ShortUInt,
    ///! An i32
    LongInt,
    ///! A u32
    LongUInt,
    ///! An i64
    LongLongInt,
    ///! A u64
    LongLongUInt,
    ///! An f32
    Float,
    ///! An f64
    Double,
    ///! A decimal value represented by a scale and a value
    DecimalValue,
    ///! Deprecated, a String
    ShortString,
    ///! A String
    LongString,
    ///! An array of AMQPValue
    FieldArray,
    ///! A timestamp (u32)
    Timestamp,
    ///! A Map<String, AMQPValue>
    FieldTable,
    ///! An array of bytes, RabbitMQ specific
    ByteArray, /* ByteArray is specific to RabbitMQ */
    ///! No value
    Void,
}

impl AMQPType {
    ///! Get the AMQPType corresponding to the given id.
    ///! We don't strictly follow the spec here but rather the RabbitMQ implementation
    ///! 's' means ShortInt (like 'U') instead of ShortString
    ///! 'l' and 'L' both mean LongLongInt (no LongLongUInt)
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    ///! Get the id from an AMQPType
    ///! We don't strictly follow the spec here but rather the RabbitMQ implementation
    ///! ShortString doesn't have an id, we return '_' instead
    ///! ShortInt is supposed to be 'U' but we use 's'
    ///! LongLongUInt is supposed to be 'L' but we return 'l' as LongLongInt
    pub fn get_id(&self) -> char {
        match *self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

///! A bool
pub type Boolean        = bool;
///! An i8
pub type ShortShortInt  = i8;
///! A u8
pub type ShortShortUInt = u8;
///! An i16
pub type ShortInt       = i16;
///! A u16
pub type ShortUInt      = u16;
///! An i32
pub type LongInt        = i32;
///! A u32
pub type LongUInt       = u32;
///! An i64
pub type LongLongInt    = i64;
///! A u64
pub type LongLongUInt   = u64;
///! A f32
pub type Float          = f32;
///! A f64
pub type Double         = f64;
///! A String (deprecated)
pub type ShortString    = String;
///! A String
pub type LongString     = String;
///! An array of AMQPValue
pub type FieldArray     = Vec<AMQPValue>;
///! A timestamp (u32)
pub type Timestamp      = LongLongUInt;
///! A Map<String, AMQPValue>
pub type FieldTable     = BTreeMap<ShortString, AMQPValue>;
///! An array of bytes (RabbitMQ specific)
pub type ByteArray      = Vec<u8>;
///! No value
pub type Void           = ();

///! A Decimal value composed of a scale and a value
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct DecimalValue {
    ///! The scale of the value
    pub scale: ShortShortUInt,
    ///! The actual value
    pub value: LongUInt,
}

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

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<|endoftext|>


<commit_before>//!
//! # Brief summary of Vulkan
//!
//! - The `Instance` object is the API entry point. It is the first object you must create before
//!   starting to use Vulkan.
//!
//! - The `PhysicalDevice` object represents an implementation of Vulkan available on the system
//!   (eg. a graphics card, a CPU implementation, multiple graphics card working together, etc.).
//!   Physical devices can be enumerated from an instance with `PhysicalDevice::enumerate()`.
//!
//! - Once you have chosen a physical device to use, you must a `Device` object from it. The
//!   `Device` is another very important object, as it represents an open channel of
//!   communicaton with the physical device.
//!
//! - `Buffer`s and `Image`s can be used to store data on memory accessible from the GPU (or
//!   Vulkan implementation). Buffers are usually used to store vertices, lights, etc. or
//!   arbitrary data, while images are used to store textures or multi-dimensional data.
//!
//! - In order to show something on the screen, you need a `Swapchain`. A `Swapchain` contains a
//!   special `Image` that corresponds to the content of the window or the monitor. When you
//!   *present* a swapchain, the content of that special image is shown on the screen.
//!
//! - `ComputePipeline`s and `GraphicsPipeline`s describe the way the GPU must perform a certain
//!   operation. `Shader`s are programs that the GPU will execute as part of a pipeline.
//!
//! - `RenderPass`es and `Framebuffer`s describe on which attachments the implementation must draw
//!   on. They are only used for graphical operations.
//!
//! - In order to ask the GPU to do something, you must create a `CommandBuffer`. A `CommandBuffer`
//!   contains a list of commands that the GPU must perform. This can include copies between
//!   buffers, compute operations, or graphics operations. For the work to start, the
//!   `CommandBuffer` must then be submitted to a `Queue`, which is obtained when you create
//!   the `Device`.
//!

//#![warn(missing_docs)]        // TODO: activate
#![allow(dead_code)]            // TODO: remove
#![allow(unused_variables)]     // TODO: remove

#[macro_use]
extern crate lazy_static;
extern crate shared_library;

#[macro_use]
mod tests;

mod features;
mod version;

pub mod buffer;
pub mod command_buffer;
pub mod descriptor_set;
pub mod device;
pub mod format;
pub mod framebuffer;
pub mod image;
pub mod instance;
pub mod memory;
pub mod pipeline;
//pub mod query;
pub mod sampler;
pub mod shader;
pub mod swapchain;
pub mod sync;

use std::error;
use std::fmt;
use std::mem;
use std::path::Path;
use std::sync::MutexGuard;

mod vk {
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_snake_case)]
    #![allow(non_camel_case_types)]
    include!(concat!(env!("OUT_DIR"), "/vk_bindings.rs"));
}

lazy_static! {
    static ref VK_LIB: shared_library::dynamic_library::DynamicLibrary = {
        #[cfg(windows)] fn get_path() -> &'static Path { Path::new("vulkan-1.dll") }
        #[cfg(unix)] fn get_path() -> &'static Path { Path::new("libvulkan-1.so") }
        let path = get_path();
        shared_library::dynamic_library::DynamicLibrary::open(Some(path)).unwrap()
    };

    static ref VK_STATIC: vk::Static = {
        vk::Static::load(|name| unsafe {
            VK_LIB.symbol(name.to_str().unwrap()).unwrap()      // TODO: error handling
        })
    };

    static ref VK_ENTRY: vk::EntryPoints = {
        vk::EntryPoints::load(|name| unsafe {
            mem::transmute(VK_STATIC.GetInstanceProcAddr(0, name.as_ptr()))
        })
    };
}

/// Gives access to the internal identifier of an object.
pub unsafe trait VulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object(&self) -> Self::Object;
}

/// Gives access to the internal identifier of an object.
pub unsafe trait SynchronizedVulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object_guard(&self) -> MutexGuard<Self::Object>;
}

// TODO: remove eventually
// https://github.com/rust-lang/rust/issues/29328
pub unsafe trait VulkanObjectU64 { fn internal_object(&self) -> u64; }
unsafe impl<T> VulkanObjectU64 for T where T: VulkanObject<Object = u64> {
    #[inline]
    fn internal_object(&self) -> u64 { VulkanObject::internal_object(self) }
}
// TODO: remove eventually
// https://github.com/rust-lang/rust/issues/29328
pub unsafe trait VulkanObjectUsize { fn internal_object(&self) -> usize; }
unsafe impl<T> VulkanObjectUsize for T where T: VulkanObject<Object = usize> {
    #[inline]
    fn internal_object(&self) -> usize { VulkanObject::internal_object(self) }
}

/// Gives access to the Vulkan function pointers stored in this object.
trait VulkanPointers {
    /// The struct that provides access to the function pointers.
    type Pointers;

    // Returns a reference to the pointers.
    fn pointers(&self) -> &Self::Pointers;
}

/// Error type returned by most Vulkan functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OomError {
    /// There is no memory available on the host (ie. the CPU, RAM, etc.).
    OutOfHostMemory,
    /// There is no memory available on the device (ie. video memory).
    OutOfDeviceMemory,
}

impl error::Error for OomError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            OomError::OutOfHostMemory => "no memory available on the host",
            OomError::OutOfDeviceMemory => "no memory available on the graphical device",
        }
    }
}

impl fmt::Display for OomError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for OomError {
    #[inline]
    fn from(err: Error) -> OomError {
        match err {
            Error::OutOfHostMemory => OomError::OutOfHostMemory,
            Error::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

/// All possible success codes returned by any Vulkan function.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
enum Success {
    Success = vk::SUCCESS,
    NotReady = vk::NOT_READY,
    Timeout = vk::TIMEOUT,
    EventSet = vk::EVENT_SET,
    EventReset = vk::EVENT_RESET,
    Incomplete = vk::INCOMPLETE,
    Suboptimal = vk::SUBOPTIMAL_KHR,
}

/// All possible errors returned by any Vulkan function.
///
/// This type is not public. Instead all public error types should implement `From<Error>` and
/// panic for error code that arent supposed to happen.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
#[doc(hidden)]      // TODO: this is necessary because of the stupid visibility rules in rustc
pub enum Error {
    OutOfHostMemory = vk::ERROR_OUT_OF_HOST_MEMORY,
    OutOfDeviceMemory = vk::ERROR_OUT_OF_DEVICE_MEMORY,
    InitializationFailed = vk::ERROR_INITIALIZATION_FAILED,
    DeviceLost = vk::ERROR_DEVICE_LOST,
    MemoryMapFailed = vk::ERROR_MEMORY_MAP_FAILED,
    LayerNotPresent = vk::ERROR_LAYER_NOT_PRESENT,
    ExtensionNotPresent = vk::ERROR_EXTENSION_NOT_PRESENT,
    FeatureNotPresent = vk::ERROR_FEATURE_NOT_PRESENT,
    IncompatibleDriver = vk::ERROR_INCOMPATIBLE_DRIVER,
    TooManyObjects = vk::ERROR_TOO_MANY_OBJECTS,
    FormatNotSupported = vk::ERROR_FORMAT_NOT_SUPPORTED,
    SurfaceLost = vk::ERROR_SURFACE_LOST_KHR,
    NativeWindowInUse = vk::ERROR_NATIVE_WINDOW_IN_USE_KHR,
    OutOfDate = vk::ERROR_OUT_OF_DATE_KHR,
    IncompatibleDisplay = vk::ERROR_INCOMPATIBLE_DISPLAY_KHR,
    ValidationFailed = vk::ERROR_VALIDATION_FAILED_EXT,
}

/// Checks whether the result returned correctly.
fn check_errors(result: vk::Result) -> Result<Success, Error> {
    match result {
        vk::SUCCESS => Ok(Success::Success),
        vk::NOT_READY => Ok(Success::NotReady),
        vk::TIMEOUT => Ok(Success::Timeout),
        vk::EVENT_SET => Ok(Success::EventSet),
        vk::EVENT_RESET => Ok(Success::EventReset),
        vk::INCOMPLETE => Ok(Success::Incomplete),
        vk::ERROR_OUT_OF_HOST_MEMORY => Err(Error::OutOfHostMemory),
        vk::ERROR_OUT_OF_DEVICE_MEMORY => Err(Error::OutOfDeviceMemory),
        vk::ERROR_INITIALIZATION_FAILED => Err(Error::InitializationFailed),
        vk::ERROR_DEVICE_LOST => Err(Error::DeviceLost),
        vk::ERROR_MEMORY_MAP_FAILED => Err(Error::MemoryMapFailed),
        vk::ERROR_LAYER_NOT_PRESENT => Err(Error::LayerNotPresent),
        vk::ERROR_EXTENSION_NOT_PRESENT => Err(Error::ExtensionNotPresent),
        vk::ERROR_FEATURE_NOT_PRESENT => Err(Error::FeatureNotPresent),
        vk::ERROR_INCOMPATIBLE_DRIVER => Err(Error::IncompatibleDriver),
        vk::ERROR_TOO_MANY_OBJECTS => Err(Error::TooManyObjects),
        vk::ERROR_FORMAT_NOT_SUPPORTED => Err(Error::FormatNotSupported),
        vk::ERROR_SURFACE_LOST_KHR => Err(Error::SurfaceLost),
        vk::ERROR_NATIVE_WINDOW_IN_USE_KHR => Err(Error::NativeWindowInUse),
        vk::SUBOPTIMAL_KHR => Ok(Success::Suboptimal),
        vk::ERROR_OUT_OF_DATE_KHR => Err(Error::OutOfDate),
        vk::ERROR_INCOMPATIBLE_DISPLAY_KHR => Err(Error::IncompatibleDisplay),
        vk::ERROR_VALIDATION_FAILED_EXT => Err(Error::ValidationFailed),
        _ => unreachable!("Unexpected error code returned by Vulkan")
    }
}
<commit_msg>Print weird returned error codes<commit_after>//!
//! # Brief summary of Vulkan
//!
//! - The `Instance` object is the API entry point. It is the first object you must create before
//!   starting to use Vulkan.
//!
//! - The `PhysicalDevice` object represents an implementation of Vulkan available on the system
//!   (eg. a graphics card, a CPU implementation, multiple graphics card working together, etc.).
//!   Physical devices can be enumerated from an instance with `PhysicalDevice::enumerate()`.
//!
//! - Once you have chosen a physical device to use, you must a `Device` object from it. The
//!   `Device` is another very important object, as it represents an open channel of
//!   communicaton with the physical device.
//!
//! - `Buffer`s and `Image`s can be used to store data on memory accessible from the GPU (or
//!   Vulkan implementation). Buffers are usually used to store vertices, lights, etc. or
//!   arbitrary data, while images are used to store textures or multi-dimensional data.
//!
//! - In order to show something on the screen, you need a `Swapchain`. A `Swapchain` contains a
//!   special `Image` that corresponds to the content of the window or the monitor. When you
//!   *present* a swapchain, the content of that special image is shown on the screen.
//!
//! - `ComputePipeline`s and `GraphicsPipeline`s describe the way the GPU must perform a certain
//!   operation. `Shader`s are programs that the GPU will execute as part of a pipeline.
//!
//! - `RenderPass`es and `Framebuffer`s describe on which attachments the implementation must draw
//!   on. They are only used for graphical operations.
//!
//! - In order to ask the GPU to do something, you must create a `CommandBuffer`. A `CommandBuffer`
//!   contains a list of commands that the GPU must perform. This can include copies between
//!   buffers, compute operations, or graphics operations. For the work to start, the
//!   `CommandBuffer` must then be submitted to a `Queue`, which is obtained when you create
//!   the `Device`.
//!

//#![warn(missing_docs)]        // TODO: activate
#![allow(dead_code)]            // TODO: remove
#![allow(unused_variables)]     // TODO: remove

#[macro_use]
extern crate lazy_static;
extern crate shared_library;

#[macro_use]
mod tests;

mod features;
mod version;

pub mod buffer;
pub mod command_buffer;
pub mod descriptor_set;
pub mod device;
pub mod format;
pub mod framebuffer;
pub mod image;
pub mod instance;
pub mod memory;
pub mod pipeline;
//pub mod query;
pub mod sampler;
pub mod shader;
pub mod swapchain;
pub mod sync;

use std::error;
use std::fmt;
use std::mem;
use std::path::Path;
use std::sync::MutexGuard;

mod vk {
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_snake_case)]
    #![allow(non_camel_case_types)]
    include!(concat!(env!("OUT_DIR"), "/vk_bindings.rs"));
}

lazy_static! {
    static ref VK_LIB: shared_library::dynamic_library::DynamicLibrary = {
        #[cfg(windows)] fn get_path() -> &'static Path { Path::new("vulkan-1.dll") }
        #[cfg(unix)] fn get_path() -> &'static Path { Path::new("libvulkan-1.so") }
        let path = get_path();
        shared_library::dynamic_library::DynamicLibrary::open(Some(path)).unwrap()
    };

    static ref VK_STATIC: vk::Static = {
        vk::Static::load(|name| unsafe {
            VK_LIB.symbol(name.to_str().unwrap()).unwrap()      // TODO: error handling
        })
    };

    static ref VK_ENTRY: vk::EntryPoints = {
        vk::EntryPoints::load(|name| unsafe {
            mem::transmute(VK_STATIC.GetInstanceProcAddr(0, name.as_ptr()))
        })
    };
}

/// Gives access to the internal identifier of an object.
pub unsafe trait VulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object(&self) -> Self::Object;
}

/// Gives access to the internal identifier of an object.
pub unsafe trait SynchronizedVulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object_guard(&self) -> MutexGuard<Self::Object>;
}

// TODO: remove eventually
// https://github.com/rust-lang/rust/issues/29328
pub unsafe trait VulkanObjectU64 { fn internal_object(&self) -> u64; }
unsafe impl<T> VulkanObjectU64 for T where T: VulkanObject<Object = u64> {
    #[inline]
    fn internal_object(&self) -> u64 { VulkanObject::internal_object(self) }
}
// TODO: remove eventually
// https://github.com/rust-lang/rust/issues/29328
pub unsafe trait VulkanObjectUsize { fn internal_object(&self) -> usize; }
unsafe impl<T> VulkanObjectUsize for T where T: VulkanObject<Object = usize> {
    #[inline]
    fn internal_object(&self) -> usize { VulkanObject::internal_object(self) }
}

/// Gives access to the Vulkan function pointers stored in this object.
trait VulkanPointers {
    /// The struct that provides access to the function pointers.
    type Pointers;

    // Returns a reference to the pointers.
    fn pointers(&self) -> &Self::Pointers;
}

/// Error type returned by most Vulkan functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OomError {
    /// There is no memory available on the host (ie. the CPU, RAM, etc.).
    OutOfHostMemory,
    /// There is no memory available on the device (ie. video memory).
    OutOfDeviceMemory,
}

impl error::Error for OomError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            OomError::OutOfHostMemory => "no memory available on the host",
            OomError::OutOfDeviceMemory => "no memory available on the graphical device",
        }
    }
}

impl fmt::Display for OomError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for OomError {
    #[inline]
    fn from(err: Error) -> OomError {
        match err {
            Error::OutOfHostMemory => OomError::OutOfHostMemory,
            Error::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

/// All possible success codes returned by any Vulkan function.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
enum Success {
    Success = vk::SUCCESS,
    NotReady = vk::NOT_READY,
    Timeout = vk::TIMEOUT,
    EventSet = vk::EVENT_SET,
    EventReset = vk::EVENT_RESET,
    Incomplete = vk::INCOMPLETE,
    Suboptimal = vk::SUBOPTIMAL_KHR,
}

/// All possible errors returned by any Vulkan function.
///
/// This type is not public. Instead all public error types should implement `From<Error>` and
/// panic for error code that arent supposed to happen.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
#[doc(hidden)]      // TODO: this is necessary because of the stupid visibility rules in rustc
pub enum Error {
    OutOfHostMemory = vk::ERROR_OUT_OF_HOST_MEMORY,
    OutOfDeviceMemory = vk::ERROR_OUT_OF_DEVICE_MEMORY,
    InitializationFailed = vk::ERROR_INITIALIZATION_FAILED,
    DeviceLost = vk::ERROR_DEVICE_LOST,
    MemoryMapFailed = vk::ERROR_MEMORY_MAP_FAILED,
    LayerNotPresent = vk::ERROR_LAYER_NOT_PRESENT,
    ExtensionNotPresent = vk::ERROR_EXTENSION_NOT_PRESENT,
    FeatureNotPresent = vk::ERROR_FEATURE_NOT_PRESENT,
    IncompatibleDriver = vk::ERROR_INCOMPATIBLE_DRIVER,
    TooManyObjects = vk::ERROR_TOO_MANY_OBJECTS,
    FormatNotSupported = vk::ERROR_FORMAT_NOT_SUPPORTED,
    SurfaceLost = vk::ERROR_SURFACE_LOST_KHR,
    NativeWindowInUse = vk::ERROR_NATIVE_WINDOW_IN_USE_KHR,
    OutOfDate = vk::ERROR_OUT_OF_DATE_KHR,
    IncompatibleDisplay = vk::ERROR_INCOMPATIBLE_DISPLAY_KHR,
    ValidationFailed = vk::ERROR_VALIDATION_FAILED_EXT,
}

/// Checks whether the result returned correctly.
fn check_errors(result: vk::Result) -> Result<Success, Error> {
    match result {
        vk::SUCCESS => Ok(Success::Success),
        vk::NOT_READY => Ok(Success::NotReady),
        vk::TIMEOUT => Ok(Success::Timeout),
        vk::EVENT_SET => Ok(Success::EventSet),
        vk::EVENT_RESET => Ok(Success::EventReset),
        vk::INCOMPLETE => Ok(Success::Incomplete),
        vk::ERROR_OUT_OF_HOST_MEMORY => Err(Error::OutOfHostMemory),
        vk::ERROR_OUT_OF_DEVICE_MEMORY => Err(Error::OutOfDeviceMemory),
        vk::ERROR_INITIALIZATION_FAILED => Err(Error::InitializationFailed),
        vk::ERROR_DEVICE_LOST => Err(Error::DeviceLost),
        vk::ERROR_MEMORY_MAP_FAILED => Err(Error::MemoryMapFailed),
        vk::ERROR_LAYER_NOT_PRESENT => Err(Error::LayerNotPresent),
        vk::ERROR_EXTENSION_NOT_PRESENT => Err(Error::ExtensionNotPresent),
        vk::ERROR_FEATURE_NOT_PRESENT => Err(Error::FeatureNotPresent),
        vk::ERROR_INCOMPATIBLE_DRIVER => Err(Error::IncompatibleDriver),
        vk::ERROR_TOO_MANY_OBJECTS => Err(Error::TooManyObjects),
        vk::ERROR_FORMAT_NOT_SUPPORTED => Err(Error::FormatNotSupported),
        vk::ERROR_SURFACE_LOST_KHR => Err(Error::SurfaceLost),
        vk::ERROR_NATIVE_WINDOW_IN_USE_KHR => Err(Error::NativeWindowInUse),
        vk::SUBOPTIMAL_KHR => Ok(Success::Suboptimal),
        vk::ERROR_OUT_OF_DATE_KHR => Err(Error::OutOfDate),
        vk::ERROR_INCOMPATIBLE_DISPLAY_KHR => Err(Error::IncompatibleDisplay),
        vk::ERROR_VALIDATION_FAILED_EXT => Err(Error::ValidationFailed),
        c => unreachable!("Unexpected error code returned by Vulkan: {}", c)
    }
}
<|endoftext|>


<commit_before>struct Stack {
    content: Vec<i32>,
    digits: Vec<i32>,
}

impl Stack {
    fn push(&mut self, d: i32) -> Result<i32, &str> {
        self.content.push(d);
        Ok(d)
    }

    fn pop(&mut self) -> Option<i32> {
        self.content.pop()
    }

    fn consume_digit(&mut self, d: i32) {
        let i = self.digits.iter().position(|&i| i == d).expect("Cannot consume!");
        self.digits.remove(i);
    }

    fn valid_digit(&self, d: i32) -> bool {
        self.digits.contains(&d)
    }

    // TODO: Also check that digits.len() == 0
    //       And return a "Result".
    fn reveal(&self) -> usize {
        self.content.len()
    }

    fn add_digit(&mut self, c: char) -> Result<i32, &str> {
        match c.to_digit(10) {
            Some(n) => match self.valid_digit(n as i32) {
                true => {
                    self.consume_digit(n as i32);
                    self.push(n as i32)
                },
                false => Err("Invalid or duplicate digit!"),
            },
            None => Err("Invalid character"),
        }
    }

    fn apply<F>(&mut self, f: F) -> Result<i32, &str>
        where F : Fn(i32, i32) -> i32 {

        let r = self.pop();
        let l = self.pop();

        match l {
            Some(n) => match r {
                Some(i) => self.push(f(n, i)),
                None => Err("Stack empty"),
            },
            None => Err("Stack empty"),
        }
    }
}

fn evaluate<'a>(program: Vec<char>, digits: Vec<i32>) -> Result<i32, &'a str> {
    let mut stack = Stack {
        content: vec![],
        digits: digits,
    };

    for c in program {
        let answer: Result<i32, &str> = match c {
            '*' => stack.apply(|l, r| l * r),
            '+' => stack.apply(|l, r| l + r),
            '-' => stack.apply(|l, r| l - r),
            '/' => stack.apply(|l, r| l / r),
            _ => stack.add_digit(c),
        };

        if answer.is_err() {
            // TODO: Fix this. Work out how to return "answer" without compiler error.
            println!("Actual: {}", answer.unwrap_err());
            return Err("Program error");
        }
    }

    match stack.reveal() {
        1 => Ok(stack.content[0]),
        _ => Err("Invalid formula"),
    }
}

fn main() {
    let program: Vec<char> = "3 2 * 4 * 1 /".chars().filter(|&c| c != ' ').collect();
    let goal: i32 = 24;
    let digits: Vec<i32> = vec![2, 3, 1, 4];

    match evaluate(program, digits) {
        Ok(n) => if n == goal {
            println!("Well done!");
        } else {
            println!("Nice try, but {} is not {}!", n, goal);
        },
        Err(s) => {
            println!("Oops: {}", s);
        },
    }
}
<commit_msg>Got reveal working with errors for invalid formulas and not using all digits<commit_after>struct Stack {
    content: Vec<i32>,
    digits: Vec<i32>,
}

impl Stack {
    fn push(&mut self, d: i32) -> Result<i32, &str> {
        self.content.push(d);
        Ok(d)
    }

    fn pop(&mut self) -> Option<i32> {
        self.content.pop()
    }

    fn consume_digit(&mut self, d: i32) {
        let i = self.digits.iter().position(|&i| i == d).expect("Cannot consume!");
        self.digits.remove(i);
    }

    fn valid_digit(&self, d: i32) -> bool {
        self.digits.contains(&d)
    }

    fn reveal<'a>(&self) -> Result<i32, &'a str> {
        match self.content.len() {
            1 => match self.digits.len() {
                0 => Ok(self.content[0]),
                _ => Err("Did not use all digits!"),
            },
            _ => Err("Invalid formula!"),
        }
    }

    fn add_digit(&mut self, c: char) -> Result<i32, &str> {
        match c.to_digit(10) {
            Some(n) => match self.valid_digit(n as i32) {
                true => {
                    self.consume_digit(n as i32);
                    self.push(n as i32)
                },
                false => Err("Invalid or duplicate digit!"),
            },
            None => Err("Invalid character"),
        }
    }

    fn apply<F>(&mut self, f: F) -> Result<i32, &str>
        where F : Fn(i32, i32) -> i32 {

        let r = self.pop();
        let l = self.pop();

        match l {
            Some(n) => match r {
                Some(i) => self.push(f(n, i)),
                None => Err("Stack empty"),
            },
            None => Err("Stack empty"),
        }
    }
}

fn evaluate<'a>(program: Vec<char>, digits: Vec<i32>) -> Result<i32, &'a str> {
    let mut stack = Stack {
        content: vec![],
        digits: digits,
    };

    for c in program {
        let answer: Result<i32, &str> = match c {
            '*' => stack.apply(|l, r| l * r),
            '+' => stack.apply(|l, r| l + r),
            '-' => stack.apply(|l, r| l - r),
            '/' => stack.apply(|l, r| l / r),
            _ => stack.add_digit(c),
        };

        if answer.is_err() {
            // TODO: Fix this. Work out how to return "answer" without compiler error.
            //return answer;
            //println!("Actual: {}", answer.unwrap_err());
            return Err("Program error");
        }
    }

    stack.reveal()
}

fn main() {
    let program: Vec<char> = "3 2 * 4 * 1 /".chars().filter(|&c| c != ' ').collect();
    let goal: i32 = 24;
    let digits: Vec<i32> = vec![2, 3, 1, 4];

    match evaluate(program, digits) {
        Ok(n) => if n == goal {
            println!("Well done!");
        } else {
            println!("Nice try, but {} is not {}!", n, goal);
        },
        Err(s) => {
            println!("Oops: {}", s);
        },
    }
}
<|endoftext|>


<commit_before>extern crate ratel;

pub use ratel::*;
pub use ratel::grammar::*;
pub use ratel::tokenizer::*;
pub use ratel::lexicon::Token;
pub use ratel::lexicon::Token::*;
pub use ratel::lexicon::ReservedKind;
pub use ratel::owned_slice::OwnedSlice;

fn test_token(input: &str, expected: Token) -> bool {
    let mut tokenizer = Tokenizer::new(&input);
    let tok = tokenizer.get_token().unwrap();
    if tok != expected {
        println!("\n{:?}\n", tok);
    }
    tok == expected
}

macro_rules! num {
    ($num:expr) => (Literal(Value::Number($num.into())))
}

macro_rules! assert_token {
    ($string:expr, $token:expr, $descr:expr) => {
        assert_eq!(test_token($string, $token), true, $descr);
    }
}

#[test]
fn test_tokenizer_chars() {
    assert_token!(";", Semicolon, "read a Semicolon");
    assert_token!(":", Colon, "read a Colon");
    assert_token!(",", Comma, "read a Comma");
    assert_token!("(", ParenOpen, "read a ParenOpen");
    assert_token!(")", ParenClose, "read a ParenClose");
    assert_token!("[", BracketOpen, "read a BracketOpen");
    assert_token!("]", BracketClose, "read a BracketClose");
    assert_token!("{", BraceOpen, "read a BraceOpen");
    assert_token!("}", BraceClose, "read a BraceClose");
}

#[test]
fn test_tokenizer_control_statements() {
    assert_token!("break", Break, "read a Break");
    assert_token!("do", Do, "read a Do");
    assert_token!("case", Case, "read a Case");
    assert_token!("else", Else, "read a Else");
    assert_token!("catch", Catch, "read a Catch");
    assert_token!("export", Export, "read a Export");
    assert_token!("class", Class, "read a Class");
    assert_token!("extends", Extends, "read a Extends");
    assert_token!("return", Return, "read a Return");
    assert_token!("while", While, "read a While");
    assert_token!("finally", Finally, "read a Finally");
    assert_token!("super", Super, "read a Super");
    assert_token!("with", With, "read a With");
    assert_token!("continue", Continue, "read a Continue");
    assert_token!("for", For, "read a For");
    assert_token!("switch", Switch, "read a Switch");
    assert_token!("yield", Yield, "read a Yield");
    assert_token!("debugger", Debugger, "read a Debugger");
    assert_token!("function", Function, "read a Function");
    assert_token!("this", This, "read a This");
    assert_token!("default", Default, "read a Default");
    assert_token!("if", If, "read a If");
    assert_token!("throw", Throw, "read a Throw");
    assert_token!("import", Import, "read a Import");
    assert_token!("try", Try, "read a Try");
}

#[test]
fn test_tokenizer_operators() {
    assert_token!("=>", Operator(OperatorType::FatArrow), "OperatorType::FatArrow");
    assert_token!(".", Operator(OperatorType::Accessor), "OperatorType::Accessor");
    assert_token!("new", Operator(OperatorType::New), "OperatorType::New");
    assert_token!("++", Operator(OperatorType::Increment), "OperatorType::Increment");
    assert_token!("--", Operator(OperatorType::Decrement), "OperatorType::Decrement");
    assert_token!("!", Operator(OperatorType::LogicalNot), "OperatorType::LogicalNot");
    assert_token!("~", Operator(OperatorType::BitwiseNot), "OperatorType::BitwiseNot");
    assert_token!("typeof", Operator(OperatorType::Typeof), "OperatorType::Typeof");
    assert_token!("void", Operator(OperatorType::Void), "OperatorType::Void");
    assert_token!("delete", Operator(OperatorType::Delete), "OperatorType::Delete");
    assert_token!("*", Operator(OperatorType::Multiplication), "OperatorType::Multiplication");
    assert_token!("/", Operator(OperatorType::Division), "OperatorType::Division");
    assert_token!("%", Operator(OperatorType::Remainder), "OperatorType::Remainder");
    assert_token!("**", Operator(OperatorType::Exponent), "OperatorType::Exponent");
    assert_token!("+", Operator(OperatorType::Addition), "OperatorType::Addition");
    assert_token!("-", Operator(OperatorType::Substraction), "OperatorType::Substraction");
    assert_token!("<<", Operator(OperatorType::BitShiftLeft), "OperatorType::BitShiftLeft");
    assert_token!(">>", Operator(OperatorType::BitShiftRight), "OperatorType::BitShiftRight");
    assert_token!(">>>", Operator(OperatorType::UBitShiftRight), "OperatorType::UBitShiftRight");
    assert_token!("<", Operator(OperatorType::Lesser), "OperatorType::Lesser");
    assert_token!("<=", Operator(OperatorType::LesserEquals), "OperatorType::LesserEquals");
    assert_token!(">", Operator(OperatorType::Greater), "OperatorType::Greater");
    assert_token!(">=", Operator(OperatorType::GreaterEquals), "OperatorType::GreaterEquals");
    assert_token!("instanceof", Operator(OperatorType::Instanceof), "OperatorType::Instanceof");
    assert_token!("in", Operator(OperatorType::In), "OperatorType::In");
    assert_token!("===", Operator(OperatorType::StrictEquality), "OperatorType::StrictEquality");
    assert_token!("!==", Operator(OperatorType::StrictInequality), "OperatorType::StrictInequality");
    assert_token!("==", Operator(OperatorType::Equality), "OperatorType::Equality");
    assert_token!("!=", Operator(OperatorType::Inequality), "OperatorType::Inequality");
    assert_token!("&", Operator(OperatorType::BitwiseAnd), "OperatorType::BitwiseAnd");
    assert_token!("^", Operator(OperatorType::BitwiseXor), "OperatorType::BitwiseXor");
    assert_token!("|", Operator(OperatorType::BitwiseOr), "OperatorType::BitwiseOr");
    assert_token!("&&", Operator(OperatorType::LogicalAnd), "OperatorType::LogicalAnd");
    assert_token!("||", Operator(OperatorType::LogicalOr), "OperatorType::LogicalOr");
    assert_token!("?", Operator(OperatorType::Conditional), "OperatorType::Conditional");
    assert_token!("=", Operator(OperatorType::Assign), "OperatorType::Assign");
    assert_token!("+=", Operator(OperatorType::AddAssign), "OperatorType::AddAssign");
    assert_token!("-=", Operator(OperatorType::SubstractAssign), "OperatorType::SubstractAssign");
    assert_token!("**=", Operator(OperatorType::ExponentAssign), "OperatorType::ExponentAssign");
    assert_token!("*=", Operator(OperatorType::MultiplyAssign), "OperatorType::MultiplyAssign");
    assert_token!("/=", Operator(OperatorType::DivideAssign), "OperatorType::DivideAssign");
    assert_token!("%=", Operator(OperatorType::RemainderAssign), "OperatorType::RemainderAssign");
    assert_token!("<<=", Operator(OperatorType::BSLAssign), "OperatorType::BSLAssign");
    assert_token!(">>=", Operator(OperatorType::BSRAssign), "OperatorType::BSRAssign");
    assert_token!(">>>=", Operator(OperatorType::UBSRAssign), "OperatorType::UBSRAssign");
    assert_token!("&=", Operator(OperatorType::BitAndAssign), "OperatorType::BitAndAssign");
    assert_token!("^=", Operator(OperatorType::BitXorAssign), "OperatorType::BitXorAssign");
    assert_token!("|=", Operator(OperatorType::BitOrAssign), "OperatorType::BitOrAssign");
    assert_token!("...", Operator(OperatorType::Spread), "OperatorType::Spread");
}

#[test]
fn test_tokenizer_literals() {
    assert_token!("undefined", Literal(Value::Undefined), "Value::Undefined");
    assert_token!("null", Literal(Value::Null), "Value::Null");
    assert_token!("true", Literal(Value::True), "Value::True");
    assert_token!("false", Literal(Value::False), "Value::False");

    assert_token!("'foo'", Literal(Value::String("'foo'".into())), "Value::String");
    assert_token!("\"foo\"", Literal(Value::String("\"foo\"".into())), "Value::String");

    assert_token!("2.2", Literal(Value::Number("2.2".into())), "Value::Number");
    assert_token!("2", Literal(Value::Number("2".into())), "Value::Number");

    assert_token!("0xff", Literal(Value::Number("255".into())), "Value::Number");
    assert_token!("0xff", num!("255"), "Value::Number");
    assert_token!("0XFF", num!("255"), "Value::Number");
    assert_token!("0b01001011", num!("75"), "Value::Number");
    assert_token!("0B01001011", num!("75"), "Value::Number");
    assert_token!("0o113", num!("75"), "Value::Number");
    assert_token!("0O113", num!("75"), "Value::Number");
}

#[test]
fn test_tokenizer_reserved() {
    assert_token!("enum", Reserved(ReservedKind::Enum), "ReservedKind::Enum");
    assert_token!("implements", Reserved(ReservedKind::Implements), "ReservedKind::Implements");
    assert_token!("package", Reserved(ReservedKind::Package), "ReservedKind::Package");
    assert_token!("protected", Reserved(ReservedKind::Protected), "ReservedKind::Protected");
    assert_token!("interface", Reserved(ReservedKind::Interface), "ReservedKind::Interface");
    assert_token!("private", Reserved(ReservedKind::Private), "ReservedKind::Private");
    assert_token!("public", Reserved(ReservedKind::Public), "ReservedKind::Public");
}

#[test]
fn test_tokenizer_whitespace() {
    assert_token!("", EndOfProgram, "empty string");
    assert_token!("  ", EndOfProgram, "whitespaces");
    assert_token!("\n\n\n  ", EndOfProgram, "newlines");
    assert_token!("//Comment\n//Comment", EndOfProgram, "single-line comment");
    assert_token!("/**\n  * Comment\n  */", EndOfProgram, "multi-line comment");
}
<commit_msg>Renaming macro in tests/tokenizer.rs<commit_after>extern crate ratel;

pub use ratel::*;
pub use ratel::grammar::*;
pub use ratel::tokenizer::*;
pub use ratel::lexicon::Token;
pub use ratel::lexicon::Token::*;
pub use ratel::lexicon::ReservedKind;
pub use ratel::owned_slice::OwnedSlice;

fn test_token(input: &str, expected: Token) -> bool {
    let mut tokenizer = Tokenizer::new(&input);
    let tok = tokenizer.get_token().unwrap();
    if tok != expected {
        println!("\n{:?}\n", tok);
    }
    tok == expected
}

macro_rules! lit_num {
    ($num:expr) => (Literal(Value::Number($num.into())))
}

macro_rules! assert_token {
    ($string:expr, $token:expr, $descr:expr) => {
        assert_eq!(test_token($string, $token), true, $descr);
    }
}

#[test]
fn test_tokenizer_chars() {
    assert_token!(";", Semicolon, "read a Semicolon");
    assert_token!(":", Colon, "read a Colon");
    assert_token!(",", Comma, "read a Comma");
    assert_token!("(", ParenOpen, "read a ParenOpen");
    assert_token!(")", ParenClose, "read a ParenClose");
    assert_token!("[", BracketOpen, "read a BracketOpen");
    assert_token!("]", BracketClose, "read a BracketClose");
    assert_token!("{", BraceOpen, "read a BraceOpen");
    assert_token!("}", BraceClose, "read a BraceClose");
}

#[test]
fn test_tokenizer_control_statements() {
    assert_token!("break", Break, "read a Break");
    assert_token!("do", Do, "read a Do");
    assert_token!("case", Case, "read a Case");
    assert_token!("else", Else, "read a Else");
    assert_token!("catch", Catch, "read a Catch");
    assert_token!("export", Export, "read a Export");
    assert_token!("class", Class, "read a Class");
    assert_token!("extends", Extends, "read a Extends");
    assert_token!("return", Return, "read a Return");
    assert_token!("while", While, "read a While");
    assert_token!("finally", Finally, "read a Finally");
    assert_token!("super", Super, "read a Super");
    assert_token!("with", With, "read a With");
    assert_token!("continue", Continue, "read a Continue");
    assert_token!("for", For, "read a For");
    assert_token!("switch", Switch, "read a Switch");
    assert_token!("yield", Yield, "read a Yield");
    assert_token!("debugger", Debugger, "read a Debugger");
    assert_token!("function", Function, "read a Function");
    assert_token!("this", This, "read a This");
    assert_token!("default", Default, "read a Default");
    assert_token!("if", If, "read a If");
    assert_token!("throw", Throw, "read a Throw");
    assert_token!("import", Import, "read a Import");
    assert_token!("try", Try, "read a Try");
}

#[test]
fn test_tokenizer_operators() {
    assert_token!("=>", Operator(OperatorType::FatArrow), "OperatorType::FatArrow");
    assert_token!(".", Operator(OperatorType::Accessor), "OperatorType::Accessor");
    assert_token!("new", Operator(OperatorType::New), "OperatorType::New");
    assert_token!("++", Operator(OperatorType::Increment), "OperatorType::Increment");
    assert_token!("--", Operator(OperatorType::Decrement), "OperatorType::Decrement");
    assert_token!("!", Operator(OperatorType::LogicalNot), "OperatorType::LogicalNot");
    assert_token!("~", Operator(OperatorType::BitwiseNot), "OperatorType::BitwiseNot");
    assert_token!("typeof", Operator(OperatorType::Typeof), "OperatorType::Typeof");
    assert_token!("void", Operator(OperatorType::Void), "OperatorType::Void");
    assert_token!("delete", Operator(OperatorType::Delete), "OperatorType::Delete");
    assert_token!("*", Operator(OperatorType::Multiplication), "OperatorType::Multiplication");
    assert_token!("/", Operator(OperatorType::Division), "OperatorType::Division");
    assert_token!("%", Operator(OperatorType::Remainder), "OperatorType::Remainder");
    assert_token!("**", Operator(OperatorType::Exponent), "OperatorType::Exponent");
    assert_token!("+", Operator(OperatorType::Addition), "OperatorType::Addition");
    assert_token!("-", Operator(OperatorType::Substraction), "OperatorType::Substraction");
    assert_token!("<<", Operator(OperatorType::BitShiftLeft), "OperatorType::BitShiftLeft");
    assert_token!(">>", Operator(OperatorType::BitShiftRight), "OperatorType::BitShiftRight");
    assert_token!(">>>", Operator(OperatorType::UBitShiftRight), "OperatorType::UBitShiftRight");
    assert_token!("<", Operator(OperatorType::Lesser), "OperatorType::Lesser");
    assert_token!("<=", Operator(OperatorType::LesserEquals), "OperatorType::LesserEquals");
    assert_token!(">", Operator(OperatorType::Greater), "OperatorType::Greater");
    assert_token!(">=", Operator(OperatorType::GreaterEquals), "OperatorType::GreaterEquals");
    assert_token!("instanceof", Operator(OperatorType::Instanceof), "OperatorType::Instanceof");
    assert_token!("in", Operator(OperatorType::In), "OperatorType::In");
    assert_token!("===", Operator(OperatorType::StrictEquality), "OperatorType::StrictEquality");
    assert_token!("!==", Operator(OperatorType::StrictInequality), "OperatorType::StrictInequality");
    assert_token!("==", Operator(OperatorType::Equality), "OperatorType::Equality");
    assert_token!("!=", Operator(OperatorType::Inequality), "OperatorType::Inequality");
    assert_token!("&", Operator(OperatorType::BitwiseAnd), "OperatorType::BitwiseAnd");
    assert_token!("^", Operator(OperatorType::BitwiseXor), "OperatorType::BitwiseXor");
    assert_token!("|", Operator(OperatorType::BitwiseOr), "OperatorType::BitwiseOr");
    assert_token!("&&", Operator(OperatorType::LogicalAnd), "OperatorType::LogicalAnd");
    assert_token!("||", Operator(OperatorType::LogicalOr), "OperatorType::LogicalOr");
    assert_token!("?", Operator(OperatorType::Conditional), "OperatorType::Conditional");
    assert_token!("=", Operator(OperatorType::Assign), "OperatorType::Assign");
    assert_token!("+=", Operator(OperatorType::AddAssign), "OperatorType::AddAssign");
    assert_token!("-=", Operator(OperatorType::SubstractAssign), "OperatorType::SubstractAssign");
    assert_token!("**=", Operator(OperatorType::ExponentAssign), "OperatorType::ExponentAssign");
    assert_token!("*=", Operator(OperatorType::MultiplyAssign), "OperatorType::MultiplyAssign");
    assert_token!("/=", Operator(OperatorType::DivideAssign), "OperatorType::DivideAssign");
    assert_token!("%=", Operator(OperatorType::RemainderAssign), "OperatorType::RemainderAssign");
    assert_token!("<<=", Operator(OperatorType::BSLAssign), "OperatorType::BSLAssign");
    assert_token!(">>=", Operator(OperatorType::BSRAssign), "OperatorType::BSRAssign");
    assert_token!(">>>=", Operator(OperatorType::UBSRAssign), "OperatorType::UBSRAssign");
    assert_token!("&=", Operator(OperatorType::BitAndAssign), "OperatorType::BitAndAssign");
    assert_token!("^=", Operator(OperatorType::BitXorAssign), "OperatorType::BitXorAssign");
    assert_token!("|=", Operator(OperatorType::BitOrAssign), "OperatorType::BitOrAssign");
    assert_token!("...", Operator(OperatorType::Spread), "OperatorType::Spread");
}

#[test]
fn test_tokenizer_literals() {
    assert_token!("undefined", Literal(Value::Undefined), "Value::Undefined");
    assert_token!("null", Literal(Value::Null), "Value::Null");
    assert_token!("true", Literal(Value::True), "Value::True");
    assert_token!("false", Literal(Value::False), "Value::False");

    assert_token!("'foo'", Literal(Value::String("'foo'".into())), "Value::String");
    assert_token!("\"foo\"", Literal(Value::String("\"foo\"".into())), "Value::String");

    assert_token!("2.2", Literal(Value::Number("2.2".into())), "Value::Number");
    assert_token!("2", Literal(Value::Number("2".into())), "Value::Number");

    assert_token!("0xff", Literal(Value::Number("255".into())), "Value::Number");
    assert_token!("0xff", lit_num!("255"), "Value::Number");
    assert_token!("0XFF", lit_num!("255"), "Value::Number");
    assert_token!("0b01001011", lit_num!("75"), "Value::Number");
    assert_token!("0B01001011", lit_num!("75"), "Value::Number");
    assert_token!("0o113", lit_num!("75"), "Value::Number");
    assert_token!("0O113", lit_num!("75"), "Value::Number");
}

#[test]
fn test_tokenizer_reserved() {
    assert_token!("enum", Reserved(ReservedKind::Enum), "ReservedKind::Enum");
    assert_token!("implements", Reserved(ReservedKind::Implements), "ReservedKind::Implements");
    assert_token!("package", Reserved(ReservedKind::Package), "ReservedKind::Package");
    assert_token!("protected", Reserved(ReservedKind::Protected), "ReservedKind::Protected");
    assert_token!("interface", Reserved(ReservedKind::Interface), "ReservedKind::Interface");
    assert_token!("private", Reserved(ReservedKind::Private), "ReservedKind::Private");
    assert_token!("public", Reserved(ReservedKind::Public), "ReservedKind::Public");
}

#[test]
fn test_tokenizer_whitespace() {
    assert_token!("", EndOfProgram, "empty string");
    assert_token!("  ", EndOfProgram, "whitespaces");
    assert_token!("\n\n\n  ", EndOfProgram, "newlines");
    assert_token!("//Comment\n//Comment", EndOfProgram, "single-line comment");
    assert_token!("/**\n  * Comment\n  */", EndOfProgram, "multi-line comment");
}
<|endoftext|>


<commit_before>use serde::{de::Deserializer, ser::Serializer};
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref, result::Result as StdResult, sync::Arc};

const CUTOFF: usize = std::mem::size_of::<&[u8]>() - 1;
type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Serialize for IVec {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serde_bytes::serialize(self.as_ref(), serializer)
    }
}

impl<'de> Deserialize<'de> for IVec {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> StdResult<Self, D::Error> {
        let bytes: StdResult<Box<[u8]>, D::Error> =
            serde_bytes::deserialize(deserializer);
        bytes.map(IVec::from)
    }
}

impl IVec {
    pub(crate) fn new(v: &[u8]) -> IVec {
        if v.len() <= CUTOFF {
            let sz = v.len() as u8;

            let mut data: Inner = [0u8; CUTOFF];

            unsafe {
                std::ptr::copy_nonoverlapping(
                    v.as_ptr(),
                    data.as_mut_ptr(),
                    v.len(),
                );
            }

            IVec(IVecInner::Inline(sz, data))
        } else {
            IVec(IVecInner::Remote(v.into()))
        }
    }

    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        if let IVecInner::Inline(..) = self.0 {
            std::mem::size_of::<IVec>() as u64
        } else {
            let sz = std::mem::size_of::<IVec>() as u64;
            sz.saturating_add(self.len() as u64)
        }
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(v: Box<[u8]>) -> IVec {
        if v.len() <= CUTOFF {
            IVec::new(&v)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            IVec(IVecInner::Remote(Arc::from(v)))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(v: &[u8]) -> IVec {
        IVec::new(v)
    }
}

impl From<&str> for IVec {
    fn from(v: &str) -> IVec {
        v.as_bytes().into()
    }
}

impl From<&IVec> for IVec {
    fn from(v: &IVec) -> IVec {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> IVec {
        v.into_boxed_slice().into()
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => unsafe {
                buf.get_unchecked(..*sz as usize)
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &IVec) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &IVec) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec { }

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1: IVec = vec![1, 2, 3].into();
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::new(&[4; 128]);
    assert_eq!(iv2, vec![4; 128]);
}
<commit_msg>Replace the IVec new constructor by the inline and remote ones<commit_after>use serde::{de::Deserializer, ser::Serializer};
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref, result::Result as StdResult, sync::Arc};

const CUTOFF: usize = std::mem::size_of::<&[u8]>() - 1;
type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Serialize for IVec {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serde_bytes::serialize(self.as_ref(), serializer)
    }
}

impl<'de> Deserialize<'de> for IVec {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> StdResult<Self, D::Error> {
        let bytes: StdResult<Box<[u8]>, D::Error> =
            serde_bytes::deserialize(deserializer);
        bytes.map(IVec::from)
    }
}

const fn is_inline_candidate(length: usize) -> bool {
    length <= CUTOFF
}

impl IVec {
    fn inline(slice: &[u8]) -> IVec {
        assert!(is_inline_candidate(slice.len()));

        let mut data = Inner::default();

        unsafe {
            std::ptr::copy_nonoverlapping(
                slice.as_ptr(),
                data.as_mut_ptr(),
                slice.len(),
            );
        }

        IVec(IVecInner::Inline(slice.len() as u8, data))
    }

    fn remote(arc: Arc<[u8]>) -> IVec {
        IVec(IVecInner::Remote(arc))
    }

    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        if let IVecInner::Inline(..) = self.0 {
            std::mem::size_of::<IVec>() as u64
        } else {
            let sz = std::mem::size_of::<IVec>() as u64;
            sz.saturating_add(self.len() as u64)
        }
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(b: Box<[u8]>) -> IVec {
        if is_inline_candidate(b.len()) {
            IVec::inline(&b)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            IVec::remote(Arc::from(b))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> IVec {
        if is_inline_candidate(slice.len()) {
            IVec::inline(slice)
        } else {
            IVec::remote(Arc::from(slice))
        }
    }
}

impl From<Arc<[u8]>> for IVec {
    fn from(arc: Arc<[u8]>) -> IVec {
        IVec::remote(arc)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> IVec {
        IVec::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &IVec) -> IVec {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> IVec {
        if is_inline_candidate(v.len()) {
            IVec::inline(&v)
        } else {
            // rely on the Arc From specialization
            // for Vec<T>, which may improve
            // over time
            IVec::remote(Arc::from(v))
        }
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => {
                unsafe { buf.get_unchecked(..*sz as usize) }
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &IVec) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &IVec) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec { }

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1 = IVec::from(vec![1, 2, 3]);
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::from(&[4; 128][..]);
    assert_eq!(iv2, vec![4; 128]);
}
<|endoftext|>


<commit_before>//! Run-time feature detection for Aarch64 on any OS that emulates the mrs instruction.
//!
//! On FreeBSD >= 12.0, Linux >= 4.11 and other operating systems, it is possible to use
//! privileged system registers from userspace to check CPU feature support.
//!
//! AArch64 system registers ID_AA64ISAR0_EL1, ID_AA64PFR0_EL1, ID_AA64ISAR1_EL1
//! have bits dedicated to features like AdvSIMD, CRC32, AES, atomics (LSE), etc.
//! Each part of the register indicates the level of support for a certain feature, e.g.
//! when ID_AA64ISAR0_EL1[7:4] is >= 1, AES is supported; when it's >= 2, PMULL is supported.
//!
//! For proper support of [SoCs where different cores have different capabilities](https://medium.com/@jadr2ddude/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb),
//! the OS has to always report only the features supported by all cores, like [FreeBSD does](https://reviews.freebsd.org/D17137#393947).
//!
//! References:
//!
//! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp)
//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt)

use crate::detect::{Feature, cache};

/// Try to read the features from the system registers.
///
/// This will cause SIGILL if the current OS is not trapping the mrs instruction.
pub(crate) fn detect_features() -> cache::Initializer {
    let mut value = cache::Initializer::default();

    {
        let mut enable_feature = |f, enable| {
            if enable {
                value.set(f as u32);
            }
        };

        // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
        let aa64isar0: u64;
        unsafe { asm!("mrs $0, ID_AA64ISAR0_EL1" : "=r"(aa64isar0)); }

        let aes = bits_shift(aa64isar0, 7, 4) >= 1;
        let pmull = bits_shift(aa64isar0, 7, 4) >= 2;
        let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
        let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
        enable_feature(Feature::pmull, pmull);
        // Crypto is specified as AES + PMULL + SHA1 + SHA2 per LLVM/hosts.cpp
        enable_feature(Feature::crypto, aes && pmull && sha1 && sha2);
        enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 1);
        enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1);

        // ID_AA64PFR0_EL1 - Processor Feature Register 0
        let aa64pfr0: u64;
        unsafe { asm!("mrs $0, ID_AA64PFR0_EL1" : "=r"(aa64pfr0)); }

        let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
        let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
        let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
        let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
        enable_feature(Feature::fp, fp);
        enable_feature(Feature::fp16, fphp);
        // SIMD support requires float support - if half-floats are
        // supported, it also requires half-float support:
        enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
        // SIMD extensions require SIMD support:
        enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
        enable_feature(Feature::dotprod, asimd && bits_shift(aa64isar0, 47, 44) >= 1);
        enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);

        // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1
        let aa64isar1: u64;
        unsafe { asm!("mrs $0, ID_AA64ISAR1_EL1" : "=r"(aa64isar1)); }

        enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1);
    }

    value
}

#[inline]
fn bits_shift(x: u64, high: usize, low: usize) -> u64 {
    (x >> low) & ((1 << (high - low + 1)) - 1)
}
<commit_msg>aarch64: escape square brackets in docs <commit_after>//! Run-time feature detection for Aarch64 on any OS that emulates the mrs instruction.
//!
//! On FreeBSD >= 12.0, Linux >= 4.11 and other operating systems, it is possible to use
//! privileged system registers from userspace to check CPU feature support.
//!
//! AArch64 system registers ID_AA64ISAR0_EL1, ID_AA64PFR0_EL1, ID_AA64ISAR1_EL1
//! have bits dedicated to features like AdvSIMD, CRC32, AES, atomics (LSE), etc.
//! Each part of the register indicates the level of support for a certain feature, e.g.
//! when ID_AA64ISAR0_EL1\[7:4\] is >= 1, AES is supported; when it's >= 2, PMULL is supported.
//!
//! For proper support of [SoCs where different cores have different capabilities](https://medium.com/@jadr2ddude/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb),
//! the OS has to always report only the features supported by all cores, like [FreeBSD does](https://reviews.freebsd.org/D17137#393947).
//!
//! References:
//!
//! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp)
//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt)

use crate::detect::{Feature, cache};

/// Try to read the features from the system registers.
///
/// This will cause SIGILL if the current OS is not trapping the mrs instruction.
pub(crate) fn detect_features() -> cache::Initializer {
    let mut value = cache::Initializer::default();

    {
        let mut enable_feature = |f, enable| {
            if enable {
                value.set(f as u32);
            }
        };

        // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
        let aa64isar0: u64;
        unsafe { asm!("mrs $0, ID_AA64ISAR0_EL1" : "=r"(aa64isar0)); }

        let aes = bits_shift(aa64isar0, 7, 4) >= 1;
        let pmull = bits_shift(aa64isar0, 7, 4) >= 2;
        let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
        let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
        enable_feature(Feature::pmull, pmull);
        // Crypto is specified as AES + PMULL + SHA1 + SHA2 per LLVM/hosts.cpp
        enable_feature(Feature::crypto, aes && pmull && sha1 && sha2);
        enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 1);
        enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1);

        // ID_AA64PFR0_EL1 - Processor Feature Register 0
        let aa64pfr0: u64;
        unsafe { asm!("mrs $0, ID_AA64PFR0_EL1" : "=r"(aa64pfr0)); }

        let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
        let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
        let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
        let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
        enable_feature(Feature::fp, fp);
        enable_feature(Feature::fp16, fphp);
        // SIMD support requires float support - if half-floats are
        // supported, it also requires half-float support:
        enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
        // SIMD extensions require SIMD support:
        enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
        enable_feature(Feature::dotprod, asimd && bits_shift(aa64isar0, 47, 44) >= 1);
        enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);

        // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1
        let aa64isar1: u64;
        unsafe { asm!("mrs $0, ID_AA64ISAR1_EL1" : "=r"(aa64isar1)); }

        enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1);
    }

    value
}

#[inline]
fn bits_shift(x: u64, high: usize, low: usize) -> u64 {
    (x >> low) & ((1 << (high - low + 1)) - 1)
}
<|endoftext|>