<commit_before>//! Implementation of event enum and event content enum macros.

use std::fmt;

use proc_macro2::Span;
use quote::{format_ident, IdentFragment};
use syn::{
    braced,
    parse::{self, Parse, ParseStream},
    Attribute, Ident, LitStr, Token,
};

/// Custom keywords for the `event_enum!` macro
mod kw {
    syn::custom_keyword!(kind);
    syn::custom_keyword!(events);
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventKindVariation {
    Full,
    Sync,
    Stripped,
    Initial,
    Redacted,
    RedactedSync,
}

impl fmt::Display for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKindVariation::Full => write!(f, ""),
            EventKindVariation::Sync => write!(f, "Sync"),
            EventKindVariation::Stripped => write!(f, "Stripped"),
            EventKindVariation::Initial => write!(f, "Initial"),
            EventKindVariation::Redacted => write!(f, "Redacted"),
            EventKindVariation::RedactedSync => write!(f, "RedactedSync"),
        }
    }
}

impl EventKindVariation {
    pub fn is_redacted(self) -> bool {
        matches!(self, Self::Redacted | Self::RedactedSync)
    }

    pub fn to_redacted(self) -> Option<Self> {
        match self {
            EventKindVariation::Full => Some(EventKindVariation::Redacted),
            EventKindVariation::Sync => Some(EventKindVariation::RedactedSync),
            _ => None,
        }
    }

    pub fn to_sync(self) -> Option<Self> {
        match self {
            EventKindVariation::Full => Some(EventKindVariation::Sync),
            EventKindVariation::Redacted => Some(EventKindVariation::RedactedSync),
            _ => None,
        }
    }

    pub fn to_full(self) -> Option<Self> {
        match self {
            EventKindVariation::Sync => Some(EventKindVariation::Full),
            EventKindVariation::RedactedSync => Some(EventKindVariation::Redacted),
            _ => None,
        }
    }
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Debug, Eq, PartialEq)]
pub enum EventKind {
    GlobalAccountData,
    RoomAccountData,
    Ephemeral,
    Message,
    State,
    ToDevice,
    RoomRedaction,
    Presence,
    Decrypted,
}

impl fmt::Display for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKind::GlobalAccountData => write!(f, "GlobalAccountDataEvent"),
            EventKind::RoomAccountData => write!(f, "RoomAccountDataEvent"),
            EventKind::Ephemeral => write!(f, "EphemeralRoomEvent"),
            EventKind::Message => write!(f, "MessageEvent"),
            EventKind::State => write!(f, "StateEvent"),
            EventKind::ToDevice => write!(f, "ToDeviceEvent"),
            EventKind::RoomRedaction => write!(f, "RoomRedactionEvent"),
            EventKind::Presence => write!(f, "PresenceEvent"),
            EventKind::Decrypted => unreachable!(),
        }
    }
}

impl IdentFragment for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }

    fn span(&self) -> Option<Span> {
        Some(Span::call_site())
    }
}

impl IdentFragment for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }

    fn span(&self) -> Option<Span> {
        Some(Span::call_site())
    }
}

impl EventKind {
    pub fn to_event_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        use EventKindVariation as V;

        // this match is only used to validate the input
        match (self, var) {
            (_, V::Full)
            | (Self::Ephemeral, V::Sync)
            | (Self::Message, V::Sync)
            | (Self::State, V::Sync)
            | (Self::State, V::Stripped)
            | (Self::State, V::Initial)
            | (Self::Message, V::Redacted)
            | (Self::RoomRedaction, V::Redacted)
            | (Self::State, V::Redacted)
            | (Self::Message, V::RedactedSync)
            | (Self::RoomRedaction, V::RedactedSync)
            | (Self::State, V::RedactedSync) => Some(format_ident!("{}{}", var, self)),
            _ => None,
        }
    }

    pub fn to_event_enum_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        Some(format_ident!("Any{}", self.to_event_ident(var)?))
    }

    /// `Any[kind]EventContent`
    pub fn to_content_enum(&self) -> Ident {
        format_ident!("Any{}Content", self)
    }
}

impl Parse for EventKind {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let ident: Ident = input.parse()?;
        Ok(match ident.to_string().as_str() {
            "GlobalAccountData" => EventKind::GlobalAccountData,
            "RoomAccountData" => EventKind::RoomAccountData,
            "EphemeralRoom" => EventKind::Ephemeral,
            "Message" => EventKind::Message,
            "State" => EventKind::State,
            "ToDevice" => EventKind::ToDevice,
            id => {
                return Err(syn::Error::new_spanned(
                    ident,
                    format!(
                        "valid event kinds are GlobalAccountData, RoomAccountData, EphemeralRoom, \
                        Message, State, ToDevice found `{}`",
                        id
                    ),
                ));
            }
        })
    }
}

// This function is only used in the `Event` derive macro expansion code.
/// Validates the given `ident` is a valid event struct name and returns a tuple of enums
/// representing the name.
pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation)> {
    let ident_str = ident.to_string();
    match ident_str.as_str() {
        "GlobalAccountDataEvent" => Some((EventKind::GlobalAccountData, EventKindVariation::Full)),
        "RoomAccountDataEvent" => Some((EventKind::RoomAccountData, EventKindVariation::Full)),
        "EphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Full)),
        "SyncEphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Sync)),
        "MessageEvent" => Some((EventKind::Message, EventKindVariation::Full)),
        "SyncMessageEvent" => Some((EventKind::Message, EventKindVariation::Sync)),
        "RedactedMessageEvent" => Some((EventKind::Message, EventKindVariation::Redacted)),
        "RedactedSyncMessageEvent" => Some((EventKind::Message, EventKindVariation::RedactedSync)),
        "StateEvent" => Some((EventKind::State, EventKindVariation::Full)),
        "SyncStateEvent" => Some((EventKind::State, EventKindVariation::Sync)),
        "StrippedStateEvent" => Some((EventKind::State, EventKindVariation::Stripped)),
        "InitialStateEvent" => Some((EventKind::State, EventKindVariation::Initial)),
        "RedactedStateEvent" => Some((EventKind::State, EventKindVariation::Redacted)),
        "RedactedSyncStateEvent" => Some((EventKind::State, EventKindVariation::RedactedSync)),
        "ToDeviceEvent" => Some((EventKind::ToDevice, EventKindVariation::Full)),
        "PresenceEvent" => Some((EventKind::Presence, EventKindVariation::Full)),
        "RoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Full)),
        "SyncRoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Sync)),
        "RedactedRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::Redacted))
        }
        "RedactedSyncRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::RedactedSync))
        }
        "DecryptedOlmV1Event" | "DecryptedMegolmV1Event" => {
            Some((EventKind::Decrypted, EventKindVariation::Full))
        }
        _ => None,
    }
}

pub struct EventEnumEntry {
    pub attrs: Vec<Attribute>,
    pub ev_type: LitStr,
}

impl Parse for EventEnumEntry {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? })
    }
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumDecl {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The event kind.
    pub kind: EventKind,

    /// An array of valid matrix event types.
    ///
    /// This will generate the variants of the event type "kind". There needs to be a corresponding
    /// variant in `ruma_events::EventType` for this event (converted to a valid Rust-style type
    /// name by stripping `m.`, replacing the remaining dots by underscores and then converting
    /// from snake_case to CamelCase).
    pub events: Vec<EventEnumEntry>,
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput {
    pub(crate) enums: Vec<EventEnumDecl>,
}

impl Parse for EventEnumInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let mut enums = vec![];
        while !input.is_empty() {
            let attrs = input.call(Attribute::parse_outer)?;

            let _: Token![enum] = input.parse()?;
            let kind: EventKind = input.parse()?;

            let content;
            braced!(content in input);
            let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
            let events = events.into_iter().collect();
            enums.push(EventEnumDecl { attrs, kind, events });
        }
        Ok(EventEnumInput { enums })
    }
}
<commit_msg>events-macros: Use nested or-patterns in EventKind::to_event_ident<commit_after>//! Implementation of event enum and event content enum macros.

use std::fmt;

use proc_macro2::Span;
use quote::{format_ident, IdentFragment};
use syn::{
    braced,
    parse::{self, Parse, ParseStream},
    Attribute, Ident, LitStr, Token,
};

/// Custom keywords for the `event_enum!` macro
mod kw {
    syn::custom_keyword!(kind);
    syn::custom_keyword!(events);
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventKindVariation {
    Full,
    Sync,
    Stripped,
    Initial,
    Redacted,
    RedactedSync,
}

impl fmt::Display for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKindVariation::Full => write!(f, ""),
            EventKindVariation::Sync => write!(f, "Sync"),
            EventKindVariation::Stripped => write!(f, "Stripped"),
            EventKindVariation::Initial => write!(f, "Initial"),
            EventKindVariation::Redacted => write!(f, "Redacted"),
            EventKindVariation::RedactedSync => write!(f, "RedactedSync"),
        }
    }
}

impl EventKindVariation {
    pub fn is_redacted(self) -> bool {
        matches!(self, Self::Redacted | Self::RedactedSync)
    }

    pub fn to_redacted(self) -> Option<Self> {
        match self {
            EventKindVariation::Full => Some(EventKindVariation::Redacted),
            EventKindVariation::Sync => Some(EventKindVariation::RedactedSync),
            _ => None,
        }
    }

    pub fn to_sync(self) -> Option<Self> {
        match self {
            EventKindVariation::Full => Some(EventKindVariation::Sync),
            EventKindVariation::Redacted => Some(EventKindVariation::RedactedSync),
            _ => None,
        }
    }

    pub fn to_full(self) -> Option<Self> {
        match self {
            EventKindVariation::Sync => Some(EventKindVariation::Full),
            EventKindVariation::RedactedSync => Some(EventKindVariation::Redacted),
            _ => None,
        }
    }
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Debug, Eq, PartialEq)]
pub enum EventKind {
    GlobalAccountData,
    RoomAccountData,
    Ephemeral,
    Message,
    State,
    ToDevice,
    RoomRedaction,
    Presence,
    Decrypted,
}

impl fmt::Display for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKind::GlobalAccountData => write!(f, "GlobalAccountDataEvent"),
            EventKind::RoomAccountData => write!(f, "RoomAccountDataEvent"),
            EventKind::Ephemeral => write!(f, "EphemeralRoomEvent"),
            EventKind::Message => write!(f, "MessageEvent"),
            EventKind::State => write!(f, "StateEvent"),
            EventKind::ToDevice => write!(f, "ToDeviceEvent"),
            EventKind::RoomRedaction => write!(f, "RoomRedactionEvent"),
            EventKind::Presence => write!(f, "PresenceEvent"),
            EventKind::Decrypted => unreachable!(),
        }
    }
}

impl IdentFragment for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }

    fn span(&self) -> Option<Span> {
        Some(Span::call_site())
    }
}

impl IdentFragment for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }

    fn span(&self) -> Option<Span> {
        Some(Span::call_site())
    }
}

impl EventKind {
    pub fn to_event_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        use EventKindVariation as V;

        // this match is only used to validate the input
        match (self, var) {
            (_, V::Full)
            | (Self::Message | Self::RoomRedaction | Self::State | Self::Ephemeral, V::Sync)
            | (Self::Message | Self::RoomRedaction | Self::State, V::Redacted | V::RedactedSync)
            | (Self::State, V::Stripped | V::Initial) => Some(format_ident!("{}{}", var, self)),
            _ => None,
        }
    }

    pub fn to_event_enum_ident(&self, var: &EventKindVariation) -> Option<Ident> {
        Some(format_ident!("Any{}", self.to_event_ident(var)?))
    }

    /// `Any[kind]EventContent`
    pub fn to_content_enum(&self) -> Ident {
        format_ident!("Any{}Content", self)
    }
}

impl Parse for EventKind {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let ident: Ident = input.parse()?;
        Ok(match ident.to_string().as_str() {
            "GlobalAccountData" => EventKind::GlobalAccountData,
            "RoomAccountData" => EventKind::RoomAccountData,
            "EphemeralRoom" => EventKind::Ephemeral,
            "Message" => EventKind::Message,
            "State" => EventKind::State,
            "ToDevice" => EventKind::ToDevice,
            id => {
                return Err(syn::Error::new_spanned(
                    ident,
                    format!(
                        "valid event kinds are GlobalAccountData, RoomAccountData, EphemeralRoom, \
                        Message, State, ToDevice found `{}`",
                        id
                    ),
                ));
            }
        })
    }
}

// This function is only used in the `Event` derive macro expansion code.
/// Validates the given `ident` is a valid event struct name and returns a tuple of enums
/// representing the name.
pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation)> {
    let ident_str = ident.to_string();
    match ident_str.as_str() {
        "GlobalAccountDataEvent" => Some((EventKind::GlobalAccountData, EventKindVariation::Full)),
        "RoomAccountDataEvent" => Some((EventKind::RoomAccountData, EventKindVariation::Full)),
        "EphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Full)),
        "SyncEphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Sync)),
        "MessageEvent" => Some((EventKind::Message, EventKindVariation::Full)),
        "SyncMessageEvent" => Some((EventKind::Message, EventKindVariation::Sync)),
        "RedactedMessageEvent" => Some((EventKind::Message, EventKindVariation::Redacted)),
        "RedactedSyncMessageEvent" => Some((EventKind::Message, EventKindVariation::RedactedSync)),
        "StateEvent" => Some((EventKind::State, EventKindVariation::Full)),
        "SyncStateEvent" => Some((EventKind::State, EventKindVariation::Sync)),
        "StrippedStateEvent" => Some((EventKind::State, EventKindVariation::Stripped)),
        "InitialStateEvent" => Some((EventKind::State, EventKindVariation::Initial)),
        "RedactedStateEvent" => Some((EventKind::State, EventKindVariation::Redacted)),
        "RedactedSyncStateEvent" => Some((EventKind::State, EventKindVariation::RedactedSync)),
        "ToDeviceEvent" => Some((EventKind::ToDevice, EventKindVariation::Full)),
        "PresenceEvent" => Some((EventKind::Presence, EventKindVariation::Full)),
        "RoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Full)),
        "SyncRoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Sync)),
        "RedactedRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::Redacted))
        }
        "RedactedSyncRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::RedactedSync))
        }
        "DecryptedOlmV1Event" | "DecryptedMegolmV1Event" => {
            Some((EventKind::Decrypted, EventKindVariation::Full))
        }
        _ => None,
    }
}

pub struct EventEnumEntry {
    pub attrs: Vec<Attribute>,
    pub ev_type: LitStr,
}

impl Parse for EventEnumEntry {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? })
    }
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumDecl {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The event kind.
    pub kind: EventKind,

    /// An array of valid matrix event types.
    ///
    /// This will generate the variants of the event type "kind". There needs to be a corresponding
    /// variant in `ruma_events::EventType` for this event (converted to a valid Rust-style type
    /// name by stripping `m.`, replacing the remaining dots by underscores and then converting
    /// from snake_case to CamelCase).
    pub events: Vec<EventEnumEntry>,
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput {
    pub(crate) enums: Vec<EventEnumDecl>,
}

impl Parse for EventEnumInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let mut enums = vec![];
        while !input.is_empty() {
            let attrs = input.call(Attribute::parse_outer)?;

            let _: Token![enum] = input.parse()?;
            let kind: EventKind = input.parse()?;

            let content;
            braced!(content in input);
            let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
            let events = events.into_iter().collect();
            enums.push(EventEnumDecl { attrs, kind, events });
        }
        Ok(EventEnumInput { enums })
    }
}
<|endoftext|>


<commit_before>use crate::common::*;
use std::process::Command;

pub fn build_and_link() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let build_dir = Path::new(&out_dir).join("libffi-build");
    let prefix = Path::new(&out_dir).join("libffi-root");
    let libdir = Path::new(&prefix).join("lib");
    let libdir64 = Path::new(&prefix).join("lib64");

    // Copy LIBFFI_DIR into build_dir to avoid an unnecessary build
    if let Err(e) = fs::remove_dir_all(&build_dir) {
        assert_eq!(
            e.kind(),
            std::io::ErrorKind::NotFound,
            "can't remove the build directory: {}",
            e
        );
    }
    run_command(
        "Copying libffi into the build directory",
        Command::new("cp").arg("-R").arg("libffi").arg(&build_dir),
    );

    // Generate configure, run configure, make, make install
    configure_libffi(prefix, &build_dir);

    run_command(
        "Building libffi",
        Command::new("make")
            .env_remove("DESTDIR")
            .arg("install")
            .current_dir(&build_dir),
    );

    // Cargo linking directives
    println!("cargo:rustc-link-lib=static=ffi");
    println!("cargo:rustc-link-search={}", libdir.display());
    println!("cargo:rustc-link-search={}", libdir64.display());
}

pub fn probe_and_link() {
    println!("cargo:rustc-link-lib=dylib=ffi");
}

pub fn configure_libffi(prefix: PathBuf, build_dir: &Path) {
    let mut command = Command::new("sh");

    command
        .arg("configure")
        .arg("--with-pic")
        .arg("--disable-docs");

    let target = std::env::var("TARGET").unwrap();
    if target != std::env::var("HOST").unwrap() {
        command.arg(format!("--host={}", target.to_string()));
    }

    command.current_dir(&build_dir);

    if cfg!(windows) {
        // When using MSYS2, OUT_DIR will be a Windows like path such as
        // C:\foo\bar. Unfortunately, the various scripts used for building
        // libffi do not like such a path, so we have to turn this into a Unix
        // like path such as /c/foo/bar.
        //
        // This code assumes the path only uses : for the drive letter, and only
        // uses \ as a component separator. It will likely break for file paths
        // that include a :.
        let mut msys_prefix = prefix
            .to_str()
            .unwrap()
            .replace(":\\", "/")
            .replace("\\", "/");

        msys_prefix.insert(0, '/');

        command.arg("--prefix").arg(msys_prefix);
    } else {
        command.arg("--prefix").arg(prefix);
    }

    run_command("Configuring libffi", &mut command);
}
<commit_msg>Fix libffi-sys-rs build on riscv64<commit_after>use crate::common::*;
use std::process::Command;

pub fn build_and_link() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let build_dir = Path::new(&out_dir).join("libffi-build");
    let prefix = Path::new(&out_dir).join("libffi-root");
    let libdir = Path::new(&prefix).join("lib");
    let libdir64 = Path::new(&prefix).join("lib64");

    // Copy LIBFFI_DIR into build_dir to avoid an unnecessary build
    if let Err(e) = fs::remove_dir_all(&build_dir) {
        assert_eq!(
            e.kind(),
            std::io::ErrorKind::NotFound,
            "can't remove the build directory: {}",
            e
        );
    }
    run_command(
        "Copying libffi into the build directory",
        Command::new("cp").arg("-R").arg("libffi").arg(&build_dir),
    );

    // Generate configure, run configure, make, make install
    configure_libffi(prefix, &build_dir);

    run_command(
        "Building libffi",
        Command::new("make")
            .env_remove("DESTDIR")
            .arg("install")
            .current_dir(&build_dir),
    );

    // Cargo linking directives
    println!("cargo:rustc-link-lib=static=ffi");
    println!("cargo:rustc-link-search={}", libdir.display());
    println!("cargo:rustc-link-search={}", libdir64.display());
}

pub fn probe_and_link() {
    println!("cargo:rustc-link-lib=dylib=ffi");
}

pub fn configure_libffi(prefix: PathBuf, build_dir: &Path) {
    let mut command = Command::new("sh");

    command
        .arg("configure")
        .arg("--with-pic")
        .arg("--disable-docs");

    let target = std::env::var("TARGET").unwrap();
    if target != std::env::var("HOST").unwrap() {
        // Autoconf uses riscv64 while Rust uses riscv64gc for the architecture
        if target == "riscv64gc-unknown-linux-gnu" {
            command.arg("--host=riscv64-unknown-linux-gnu");
        } else {
            command.arg(format!("--host={}", target));
        }
    }

    command.current_dir(&build_dir);

    if cfg!(windows) {
        // When using MSYS2, OUT_DIR will be a Windows like path such as
        // C:\foo\bar. Unfortunately, the various scripts used for building
        // libffi do not like such a path, so we have to turn this into a Unix
        // like path such as /c/foo/bar.
        //
        // This code assumes the path only uses : for the drive letter, and only
        // uses \ as a component separator. It will likely break for file paths
        // that include a :.
        let mut msys_prefix = prefix
            .to_str()
            .unwrap()
            .replace(":\\", "/")
            .replace("\\", "/");

        msys_prefix.insert(0, '/');

        command.arg("--prefix").arg(msys_prefix);
    } else {
        command.arg("--prefix").arg(prefix);
    }

    run_command("Configuring libffi", &mut command);
}
<|endoftext|>


<commit_before>#![allow(unstable)]

use std::io::{self, fs};
use std::io::process::{Command, InheritFd};
use std::os;

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
            .stderr(InheritFd(2))
            .status()
            .unwrap()
            .success());
}

fn main() {
    let cwd = os::getcwd().unwrap();

    let root_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let out_dir = Path::new(os::getenv("OUT_DIR").expect("out dir must be specified"));

    let build_dir = out_dir.join("build");
    assert!(fs::mkdir_recursive(&build_dir, io::USER_DIR).is_ok());
    assert!(os::change_dir(&build_dir).is_ok());

    let lib_dir = out_dir.join("lib");
    assert!(fs::mkdir_recursive(&lib_dir, io::USER_DIR).is_ok());

    run(Command::new("cmake")
        .arg(root_dir.join("forestdb"))
        .arg("-DCMAKE_BUILD_TYPE=Release") // FIXME: use env for determine type
        .arg(format!("-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}", lib_dir.display())));

    run(&mut Command::new("make"));

    let _ = os::change_dir(&cwd);

    println!("cargo:rustc-flags=-l forestdb -L {}", lib_dir.display());
}
<commit_msg>Disable snappy for a while<commit_after>#![allow(unstable)]

use std::io::{self, fs};
use std::io::process::{Command, InheritFd};
use std::os;

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
            .stderr(InheritFd(2))
            .status()
            .unwrap()
            .success());
}

fn main() {
    let cwd = os::getcwd().unwrap();

    let root_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let out_dir = Path::new(os::getenv("OUT_DIR").expect("out dir must be specified"));

    let build_dir = out_dir.join("build");
    assert!(fs::mkdir_recursive(&build_dir, io::USER_DIR).is_ok());
    assert!(os::change_dir(&build_dir).is_ok());

    let lib_dir = out_dir.join("lib");
    assert!(fs::mkdir_recursive(&lib_dir, io::USER_DIR).is_ok());

    run(Command::new("cmake")
        .arg(root_dir.join("forestdb"))
        .arg("-DCMAKE_BUILD_TYPE=Release") // FIXME: use env for determine type
        .arg(format!("-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}", lib_dir.display()))
        .arg("-DSNAPPY_OPTION=Disable"));

    run(&mut Command::new("make"));

    let _ = os::change_dir(&cwd);

    println!("cargo:rustc-flags=-l forestdb -L {}", lib_dir.display());
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    actor::{self, SharedState},
    Idle, Poll, PrepareDownload, Result, State, StateChangeImpl, StateMachine,
};
use crate::client::{Api, ProbeResponse};
use chrono::{Duration, Utc};
use slog_scope::{debug, error, info};

#[derive(Debug, PartialEq)]
pub(super) struct Probe;

create_state_step!(Probe => Idle);
create_state_step!(Probe => Poll);

/// Implements the state change for State<Probe>.
#[async_trait::async_trait]
impl StateChangeImpl for State<Probe> {
    fn name(&self) -> &'static str {
        "probe"
    }

    fn handle_trigger_probe(&self) -> actor::probe::Response {
        actor::probe::Response::RequestAccepted(self.name().to_owned())
    }

    async fn handle(
        self,
        shared_state: &mut SharedState,
    ) -> Result<(StateMachine, actor::StepTransition)> {
        let server_address = shared_state.server_address();

        let probe = match Api::new(&server_address)
            .probe(&shared_state.runtime_settings, &shared_state.firmware)
            .await
        {
            Err(e) => {
                error!("{}", e);
                shared_state.runtime_settings.inc_retries();
                return Ok((
                    StateMachine::Probe(self),
                    actor::StepTransition::Delayed(std::time::Duration::from_secs(1)),
                ));
            }
            Ok(probe) => probe,
        };
        shared_state.runtime_settings.clear_retries();

        match probe {
            ProbeResponse::NoUpdate => {
                debug!("Moving to Idle state as no update is available.");

                // Store timestamp of last polling
                shared_state.runtime_settings.set_last_polling(Utc::now())?;
                Ok((StateMachine::Idle(self.into()), actor::StepTransition::Immediate))
            }

            ProbeResponse::ExtraPoll(s) => {
                info!("Delaying the probing as requested by the server.");
                shared_state.runtime_settings.set_polling_extra_interval(Duration::seconds(s))?;

                debug!("Moving to Poll state due the extra polling interval.");
                Ok((StateMachine::Poll(self.into()), actor::StepTransition::Immediate))
            }

            ProbeResponse::Update(u) => {
                // Ensure the package is compatible
                u.compatible_with(&shared_state.firmware)?;
                // Store timestamp of last polling
                shared_state.runtime_settings.set_last_polling(Utc::now())?;

                if Some(u.package_uid()) == shared_state.runtime_settings.applied_package_uid() {
                    info!(
                        "Not applying the update package. Same package has already been installed."
                    );
                    debug!("Moving to Idle state as this update package is already installed.");
                    Ok((StateMachine::Idle(self.into()), actor::StepTransition::Immediate))
                } else {
                    debug!("Moving to PrepareDownload state to process the update package.");
                    Ok((
                        StateMachine::PrepareDownload(State(PrepareDownload { update_package: u })),
                        actor::StepTransition::Immediate,
                    ))
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        client::tests::{create_mock_server, FakeServer},
        firmware::{
            tests::{create_fake_metadata, FakeDevice},
            Metadata,
        },
        runtime_settings::RuntimeSettings,
        settings::Settings,
    };
    use std::fs;
    use tempfile::NamedTempFile;

    #[actix_rt::test]
    async fn update_not_available() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::NoUpdate);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Idle);
    }

    #[actix_rt::test]
    async fn update_available() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::HasUpdate);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::HasUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, PrepareDownload);
    }

    #[actix_rt::test]
    async fn invalid_hardware() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::InvalidHardware);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware =
            Metadata::from_path(&create_fake_metadata(FakeDevice::InvalidHardware)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine =
            StateMachine::Probe(State(Probe {})).move_to_next_state(&mut shared_state).await;

        mock.assert();

        assert!(machine.is_err(), "Did not catch an incompatible hardware");
    }

    #[actix_rt::test]
    async fn extra_poll_interval() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::ExtraPoll);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::ExtraPoll)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Poll);
    }

    #[actix_rt::test]
    async fn skip_same_package_uid() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::HasUpdate).expect(2);

        let mut runtime_settings = RuntimeSettings::load(tmpfile).unwrap();

        // We first get the package_uid that will be returned so we can
        // use it for the upcoming test.
        //
        // This has been done so we don't need to manually update it every
        // time we change the package payload.
        let probe = Api::new(&Settings::default().network.server_address)
            .probe(
                &RuntimeSettings::default(),
                &Metadata::from_path(&create_fake_metadata(FakeDevice::HasUpdate)).unwrap(),
            )
            .await
            .unwrap();

        if let ProbeResponse::Update(u) = probe {
            runtime_settings.set_applied_package_uid(&u.package_uid()).unwrap();
        }

        let settings = Settings::default();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::HasUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Idle);
    }

    #[actix_rt::test]
    async fn error() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        // The server here waits for the second request which includes the
        // retries to succeed.
        let mock = create_mock_server(FakeServer::ErrorOnce);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Idle);
    }
}
<commit_msg>updatehub: Fix probe getting stuck when server url is invalid<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    actor::{self, SharedState},
    Idle, Poll, PrepareDownload, Result, State, StateChangeImpl, StateMachine,
};
use crate::client::{self, Api, ProbeResponse};
use chrono::{Duration, Utc};
use slog_scope::{debug, error, info};

#[derive(Debug, PartialEq)]
pub(super) struct Probe;

create_state_step!(Probe => Idle);
create_state_step!(Probe => Poll);

/// Implements the state change for State<Probe>.
#[async_trait::async_trait]
impl StateChangeImpl for State<Probe> {
    fn name(&self) -> &'static str {
        "probe"
    }

    fn handle_trigger_probe(&self) -> actor::probe::Response {
        actor::probe::Response::RequestAccepted(self.name().to_owned())
    }

    async fn handle(
        self,
        shared_state: &mut SharedState,
    ) -> Result<(StateMachine, actor::StepTransition)> {
        let server_address = shared_state.server_address();

        let probe = match Api::new(&server_address)
            .probe(&shared_state.runtime_settings, &shared_state.firmware)
            .await
        {
            Err(client::Error::Client(e)) if e.is_builder() => {
                return Err(client::Error::Client(e).into());
            }
            Err(e) => {
                error!("Probe failed: {}", e);
                shared_state.runtime_settings.inc_retries();
                return Ok((
                    StateMachine::Probe(self),
                    actor::StepTransition::Delayed(std::time::Duration::from_secs(1)),
                ));
            }
            Ok(probe) => probe,
        };
        shared_state.runtime_settings.clear_retries();

        match probe {
            ProbeResponse::NoUpdate => {
                debug!("Moving to Idle state as no update is available.");

                // Store timestamp of last polling
                shared_state.runtime_settings.set_last_polling(Utc::now())?;
                Ok((StateMachine::Idle(self.into()), actor::StepTransition::Immediate))
            }

            ProbeResponse::ExtraPoll(s) => {
                info!("Delaying the probing as requested by the server.");
                shared_state.runtime_settings.set_polling_extra_interval(Duration::seconds(s))?;

                debug!("Moving to Poll state due the extra polling interval.");
                Ok((StateMachine::Poll(self.into()), actor::StepTransition::Immediate))
            }

            ProbeResponse::Update(u) => {
                // Ensure the package is compatible
                u.compatible_with(&shared_state.firmware)?;
                // Store timestamp of last polling
                shared_state.runtime_settings.set_last_polling(Utc::now())?;

                if Some(u.package_uid()) == shared_state.runtime_settings.applied_package_uid() {
                    info!(
                        "Not applying the update package. Same package has already been installed."
                    );
                    debug!("Moving to Idle state as this update package is already installed.");
                    Ok((StateMachine::Idle(self.into()), actor::StepTransition::Immediate))
                } else {
                    debug!("Moving to PrepareDownload state to process the update package.");
                    Ok((
                        StateMachine::PrepareDownload(State(PrepareDownload { update_package: u })),
                        actor::StepTransition::Immediate,
                    ))
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        client::tests::{create_mock_server, FakeServer},
        firmware::{
            tests::{create_fake_metadata, FakeDevice},
            Metadata,
        },
        runtime_settings::RuntimeSettings,
        settings::Settings,
    };
    use std::fs;
    use tempfile::NamedTempFile;

    #[actix_rt::test]
    async fn update_not_available() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::NoUpdate);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Idle);
    }

    #[actix_rt::test]
    async fn update_available() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::HasUpdate);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::HasUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, PrepareDownload);
    }

    #[actix_rt::test]
    async fn invalid_hardware() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::InvalidHardware);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware =
            Metadata::from_path(&create_fake_metadata(FakeDevice::InvalidHardware)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine =
            StateMachine::Probe(State(Probe {})).move_to_next_state(&mut shared_state).await;

        mock.assert();

        assert!(machine.is_err(), "Did not catch an incompatible hardware");
    }

    #[actix_rt::test]
    async fn extra_poll_interval() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::ExtraPoll);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::ExtraPoll)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Poll);
    }

    #[actix_rt::test]
    async fn skip_same_package_uid() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        let mock = create_mock_server(FakeServer::HasUpdate).expect(2);

        let mut runtime_settings = RuntimeSettings::load(tmpfile).unwrap();

        // We first get the package_uid that will be returned so we can
        // use it for the upcoming test.
        //
        // This has been done so we don't need to manually update it every
        // time we change the package payload.
        let probe = Api::new(&Settings::default().network.server_address)
            .probe(
                &RuntimeSettings::default(),
                &Metadata::from_path(&create_fake_metadata(FakeDevice::HasUpdate)).unwrap(),
            )
            .await
            .unwrap();

        if let ProbeResponse::Update(u) = probe {
            runtime_settings.set_applied_package_uid(&u.package_uid()).unwrap();
        }

        let settings = Settings::default();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::HasUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Idle);
    }

    #[actix_rt::test]
    async fn error() {
        let tmpfile = NamedTempFile::new().unwrap();
        let tmpfile = tmpfile.path();
        fs::remove_file(&tmpfile).unwrap();

        // The server here waits for the second request which includes the
        // retries to succeed.
        let mock = create_mock_server(FakeServer::ErrorOnce);

        let settings = Settings::default();
        let runtime_settings = RuntimeSettings::load(tmpfile).unwrap();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::Probe(State(Probe {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        mock.assert();

        assert_state!(machine, Idle);
    }
}
<|endoftext|>


<commit_before>use assembler::x64::{Addr, R64};
use assembler::x64::R64::*;
use assembler::x64::traits::*;
use assembler::emit::{Emit, Label};

use template_interp::shared::{Dispatchable, build_interp, breakpoint};

use std::mem;
use std::env;
use std::collections::HashSet;

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
enum Op {
    // stack.push(oparg_i8)
    LoadI8 = 0,

    // stack.push(stack[oparg_i8])
    LoadL,

    // r = stack.pop(); l = stack.pop(); if l < r then pc += oparg_i8
    BranchLt,

    // Callee clears the stack.
    // func_ix = oparg_u8; stack.push(pc); pc = func_table[oparg_u8]; locals = args
    Call,

    // res = stack.pop(); pc = stack.pop(); stack.pops(oparg_u8); stack.push(res)
    Ret,

    // rax = stack.pop(); halt
    Halt,

    // r = stack.pop(); l = stack.pop(); stack.push(l + r)
    Add,
}

#[derive(Debug, Clone, Copy)]
enum Instr {
    OpOnly(Op),
    OpWithArg(Op, i8),
}

fn instr_to_bs(is: &[Instr]) -> Vec<u8> {
    let mut bs = vec![];
    for i in is {
        match i {
            &Instr::OpOnly(op) => {
                bs.push(op as u8);
            }
            &Instr::OpWithArg(op, arg) => {
                bs.push(op as u8);
                bs.push(arg as u8);
            }
        }
    }
    bs
}

const LAST_OP: Op = Op::Add;

#[repr(C)]
struct InterpContext {
    pc: isize,
    dispatch_table: isize,
    func_table: isize,
    trace_ctx: isize,
    sp: isize,
}

// Can we have offsetof?
const PC_OFFSET: i32 = 0;
const DT_OFFSET: i32 = 1 * 8;
const FT_OFFSET: i32 = 2 * 8;
const TC_OFFSET: i32 = 3 * 8;
const SP_OFFSET: i32 = 4 * 8;

impl InterpContext {
    fn location_mapping(base: R64, vr: &VMRegs) -> Vec<(R64, Addr)>{
        vec![
            (vr.pc, base + PC_OFFSET),
            (vr.dispatch_table, base + DT_OFFSET),
            (vr.func_table, base + FT_OFFSET),
            (vr.trace_ctx, base + TC_OFFSET),
            (vr.sp, base + SP_OFFSET),
        ]
    }

    fn build_unpack_to_reg(emit: &mut Emit, vr: &VMRegs) {
        // TODO
        let mut last_move: Option<Box<FnMut(&mut Emit)>> = None;
        for (r, m) in InterpContext::location_mapping(rdi, vr) {
            if r == rdi {
                last_move = Some(Box::new(move |emit| {
                    emit.mov(r, &m);
                }));
            } else {
                emit.mov(r, &m);
            }
        }
        if let Some(mut f) = last_move {
            f(emit);
        }
    }
}

#[derive(Debug)]
struct Trace {
    bc_list: Vec<isize>,
    bc_set: HashSet<isize>,
}

impl Trace {
    fn new() -> Self {
        Trace {
            bc_list: Default::default(),
            bc_set: Default::default(),
        }
    }

    // Returns false if this trace is finished.
    fn record(&mut self, bc_ptr: isize) -> bool {
        self.bc_list.push(bc_ptr);
        if self.bc_set.contains(&bc_ptr) {
            return false;
        }
        self.bc_set.insert(bc_ptr);
        true
    }
}

#[derive(Debug)]
struct TraceContext {
    current: Trace,
    traces: Vec<Trace>,
}

impl TraceContext {
    fn new() -> Box<Self> {
        Box::new(TraceContext {
            current: Trace::new(),
            traces: vec![],
        })
    }

    fn as_ptr(&self) -> *const Self {
        self as *const _
    }

    fn record(&mut self, bc_ptr: isize) {
        if !self.current.record(bc_ptr) {
            let mut new_trace = Trace::new();
            mem::swap(&mut self.current, &mut new_trace);
            self.traces.push(new_trace);

            // Shall we record the trace bridge?
            self.record(bc_ptr);
        }
    }

    pub unsafe extern "C" fn record_unsafe(raw: *mut TraceContext, bc_ptr: isize) {
        (&mut *raw).record(bc_ptr);
    }
}

struct VMRegs {
    pc: R64,
    tmpl: R64,
    tmpr: R64,
    dispatch_table: R64,
    func_table: R64,
    trace_ctx: R64,
    sp: R64,
    scratch: R64,
}

impl VMRegs {
    fn new() -> Self {
        VMRegs {
            pc: rdi,
            dispatch_table: rsi,
            func_table: rdx,
            tmpl: rcx,
            tmpr: r8,
            trace_ctx: r9,
            sp: r10,
            scratch: r11,
        }
    }

    fn regs(&self) -> Vec<R64> {
        vec![self.pc, self.dispatch_table, self.func_table, self.tmpr, self.tmpl, self.trace_ctx]
    }
}

struct Opts {
    duplicate_branch_op_tails: bool,
    trace_on: bool,
}

impl Opts {
    fn new() -> Self {
        Opts {
            duplicate_branch_op_tails: true,
            trace_on: false,
        }
    }
}

impl From<u8> for Op {
    fn from(repr: u8) -> Self {
        Op::from_u8(repr)
    }
}

impl From<Op> for u8 {
    fn from(repr: Op) -> Self {
        repr as u8
    }
}

impl Dispatchable<(VMRegs, Opts)> for Op {
    fn build_interp_entry(emit: &mut Emit, args: &(VMRegs, Opts)) {
        InterpContext::build_unpack_to_reg(emit, &args.0);
    }

    fn build_dispatch_case(self, emit: &mut Emit, args: &(VMRegs, Opts)) {
        Op::build_dispatch_case(self, emit, &args.0, &args.1);
    }

    fn build_dispatch_with_pc_offset(emit: &mut Emit, args: &(VMRegs, Opts), offset: i32) {
        build_dispatch_with_pc_offset(emit, &args.0, &args.1, offset);
    }
}

impl Op {
    fn from_u8(repr: u8) -> Self {
        unsafe { mem::transmute(repr) }
    }

    fn build_dispatch_case(self, emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
        use self::Op::*;

        fn push_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(&(vr.sp + (-8)), r)
                .sub(vr.sp, 8);
        }

        fn push_a(emit: &mut Emit, vr: &VMRegs, a: &Addr) {
            emit.mov(vr.scratch, a)
                .mov(&(vr.sp + (-8)), vr.scratch)
                .sub(vr.sp, 8);
        }

        fn pop_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(r, &Addr::B(vr.sp))
                .add(vr.sp, 8);
        }

        match self {
            LoadI8 => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            LoadL => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_a(emit, vr, &(vr.sp + vr.tmpl * 8));
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            BranchLt => {
                pop_r(emit, vr, vr.tmpr);
                pop_r(emit, vr, vr.tmpl);
                emit.cmp(vr.tmpl, vr.tmpr);

                if opts.duplicate_branch_op_tails {
                    let mut lt = Label::new();
                    emit.jl(&mut lt);
                    build_dispatch_skip_oparg(emit, vr, opts);
                    emit.bind(&mut lt)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl);
                    build_dispatch_skip_oparg(emit, vr, opts);
                } else {
                    let mut ge = Label::new();
                    emit.jge(&mut ge)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl)
                        .bind(&mut ge);
                    build_dispatch_skip_oparg(emit, vr, opts);
                }
            }
            Call => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .add(vr.pc, 2);

                push_r(emit, vr, vr.pc);
                emit.mov(vr.pc, &(vr.func_table + vr.tmpl * 8));
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Ret => {
                pop_r(emit, vr, vr.tmpl);
                emit.movsb(vr.tmpr, &(vr.pc + 1));
                pop_r(emit, vr, vr.pc);
                emit.lea(vr.sp, &(vr.sp + vr.tmpr * 8));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Halt => {
                pop_r(emit, vr, rax);
                emit.ret();
            }
            Add => {
                pop_r(emit, vr, vr.tmpr);
                emit.add(&Addr::B(vr.sp), vr.tmpr);
                build_dispatch_with_pc_offset(emit, vr, opts, 1);
            }
        }
    }

}

fn build_dispatch_with_pc_offset(emit: &mut Emit, vr: &VMRegs, opts: &Opts, offset: i32) {
    if offset == 0 {
        emit.movsb(vr.tmpl, &Addr::B(vr.pc));
    } else {
        emit.movsb(vr.tmpl, &(vr.pc + offset))
            .add(vr.pc, offset);
    }

    // Like PyPy's jit_merge_point
    if opts.trace_on {
        let rs = vr.regs();
        for r in &rs {
            emit.push(*r);
        }

        let mut moar_pops: Box<FnMut(&mut Emit)> = if rs.len() % 2 == 0 {
            // Stack alignment
            emit.push(rax);
            Box::new(|emit| { emit.pop(rax); })
        } else {
            Box::new(|_| ())
        };

        emit.mov(rsi, vr.pc)  // Since pc == rdi. XXX: hardcoded...
            .mov(rdi, vr.trace_ctx)
            .mov(rax, unsafe { mem::transmute::<_, i64>(TraceContext::record_unsafe) })
            .call(rax);

        moar_pops(emit);

        for r in rs.iter().rev() {
            emit.pop(*r);
        }
    }

    emit.jmp(&(vr.dispatch_table + vr.tmpl * 8));
}

fn build_dispatch_skip_oparg(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 2)
}

fn build_dispatch_correct_pc(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 0)
}

pub fn main(n: u8) {
    use self::Instr::*;
    use self::Op::*;

    let mut opts = Opts::new();
    if env::var("NO_DUP_BR_TAILS").is_ok() {
        opts.duplicate_branch_op_tails = false;
    };

    if env::var("TRACE_ON").is_ok() {
        opts.trace_on = true;
    };

    let (labels, jm) = build_interp(LAST_OP, &(VMRegs::new(), opts));

    let main_code = instr_to_bs(&[
        OpWithArg(LoadI8, n as i8),
        OpWithArg(Call, 1),
        OpOnly(Halt),
    ]);

    let id_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let fibo_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, 2),
        OpWithArg(BranchLt, 17),

        // Recur case.
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, -1),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpWithArg(LoadL, 2),
        OpWithArg(LoadI8, -2),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpOnly(Add),
        OpWithArg(Ret, 1),

        // Base case.
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let func_table = [
        id_code.as_ptr(),
        fibo_code.as_ptr(),
    ];

    let trace_ctx = TraceContext::new();

    let stack = [0_isize; 1024];

    let res = unsafe {
        let pc = main_code.as_ptr() as isize;
        let lbl_ptr = labels.as_ptr() as isize;
        let func_table_ptr = func_table.as_ptr() as isize;
        let trace_ctx_ptr = trace_ctx.as_ptr() as isize;
        let stack_ptr = stack.as_ptr().offset(stack.len() as isize) as isize;
        let ictx = InterpContext {
            pc: pc,
            func_table: func_table_ptr,
            trace_ctx: trace_ctx_ptr,
            dispatch_table: lbl_ptr,
            sp: stack_ptr,
        };
        if env::var("BREAK").is_ok() {
            breakpoint();
        }
        jm.call_ptr_ptr(&ictx as *const _ as isize)
    };
    println!("res = {}", res);
    println!("trace = {:?}", trace_ctx);
}
<commit_msg>pprint the traces to see what was going wrong..<commit_after>use assembler::x64::{Addr, R64};
use assembler::x64::R64::*;
use assembler::x64::traits::*;
use assembler::emit::{Emit, Label};

use template_interp::shared::{Dispatchable, build_interp, breakpoint};

use std::mem;
use std::fmt::{self, Display};
use std::env;
use std::collections::HashSet;

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
enum Op {
    // stack.push(oparg_i8)
    LoadI8 = 0,

    // stack.push(stack[oparg_i8])
    LoadL,

    // r = stack.pop(); l = stack.pop(); if l < r then pc += oparg_i8
    BranchLt,

    // Callee clears the stack.
    // func_ix = oparg_u8; stack.push(pc); pc = func_table[oparg_u8]; locals = args
    Call,

    // res = stack.pop(); pc = stack.pop(); stack.pops(oparg_u8); stack.push(res)
    Ret,

    // rax = stack.pop(); halt
    Halt,

    // r = stack.pop(); l = stack.pop(); stack.push(l + r)
    Add,
}

#[derive(Debug, Clone, Copy)]
enum Instr {
    OpOnly(Op),
    OpWithArg(Op, i8),
}

fn instr_to_bs(is: &[Instr]) -> Vec<u8> {
    let mut bs = vec![];
    for i in is {
        match i {
            &Instr::OpOnly(op) => {
                bs.push(op as u8);
            }
            &Instr::OpWithArg(op, arg) => {
                bs.push(op as u8);
                bs.push(arg as u8);
            }
        }
    }
    bs
}

const LAST_OP: Op = Op::Add;

#[repr(C)]
struct InterpContext {
    pc: isize,
    dispatch_table: isize,
    func_table: isize,
    trace_ctx: isize,
    sp: isize,
}

// Can we have offsetof?
const PC_OFFSET: i32 = 0;
const DT_OFFSET: i32 = 1 * 8;
const FT_OFFSET: i32 = 2 * 8;
const TC_OFFSET: i32 = 3 * 8;
const SP_OFFSET: i32 = 4 * 8;

impl InterpContext {
    fn location_mapping(base: R64, vr: &VMRegs) -> Vec<(R64, Addr)>{
        vec![
            (vr.pc, base + PC_OFFSET),
            (vr.dispatch_table, base + DT_OFFSET),
            (vr.func_table, base + FT_OFFSET),
            (vr.trace_ctx, base + TC_OFFSET),
            (vr.sp, base + SP_OFFSET),
        ]
    }

    fn build_unpack_to_reg(emit: &mut Emit, vr: &VMRegs) {
        // TODO
        let mut last_move: Option<Box<FnMut(&mut Emit)>> = None;
        for (r, m) in InterpContext::location_mapping(rdi, vr) {
            if r == rdi {
                last_move = Some(Box::new(move |emit| {
                    emit.mov(r, &m);
                }));
            } else {
                emit.mov(r, &m);
            }
        }
        if let Some(mut f) = last_move {
            f(emit);
        }
    }
}

#[derive(Debug)]
struct Trace {
    bc_list: Vec<isize>,
    bc_set: HashSet<isize>,
}

impl Display for Trace {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "Trace {{ "));
        for ptr in &self.bc_list {
            unsafe {
                try!(Op::display_ptr(*ptr, fmt));
                try!(write!(fmt, " "));
            }
        }
        try!(write!(fmt, "}}"));
        Ok(())
    }
}

impl Trace {
    fn new() -> Self {
        Trace {
            bc_list: Default::default(),
            bc_set: Default::default(),
        }
    }

    // Returns false if this trace is finished.
    fn record(&mut self, bc_ptr: isize) -> bool {
        self.bc_list.push(bc_ptr);
        if self.bc_set.contains(&bc_ptr) {
            return false;
        }
        self.bc_set.insert(bc_ptr);
        true
    }
}

#[derive(Debug)]
struct TraceContext {
    current: Trace,
    traces: Vec<Trace>,
}

impl Display for TraceContext {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "TraceContext {{ traces: "));
        for trace in &self.traces {
            try!(write!(fmt, "{} ", trace));
        }
        try!(write!(fmt, ", current: {} ", &self.current));
        try!(write!(fmt, "}}"));
        Ok(())
    }
}

impl TraceContext {
    fn new() -> Box<Self> {
        Box::new(TraceContext {
            current: Trace::new(),
            traces: vec![],
        })
    }

    fn as_ptr(&self) -> *const Self {
        self as *const _
    }

    fn record(&mut self, bc_ptr: isize) {
        if !self.current.record(bc_ptr) {
            let mut new_trace = Trace::new();
            mem::swap(&mut self.current, &mut new_trace);
            self.traces.push(new_trace);

            // Shall we record the trace bridge?
            self.record(bc_ptr);
        }
    }

    pub unsafe extern "C" fn record_unsafe(raw: *mut TraceContext, bc_ptr: isize) {
        (&mut *raw).record(bc_ptr);
    }
}

struct VMRegs {
    pc: R64,
    tmpl: R64,
    tmpr: R64,
    dispatch_table: R64,
    func_table: R64,
    trace_ctx: R64,
    sp: R64,
    scratch: R64,
}

impl VMRegs {
    fn new() -> Self {
        VMRegs {
            pc: rdi,
            dispatch_table: rsi,
            func_table: rdx,
            tmpl: rcx,
            tmpr: r8,
            trace_ctx: r9,
            sp: r10,
            scratch: r11,
        }
    }

    fn regs(&self) -> Vec<R64> {
        vec![self.pc, self.dispatch_table, self.func_table, self.tmpr, self.tmpl, self.trace_ctx]
    }
}

struct Opts {
    duplicate_branch_op_tails: bool,
    trace_on: bool,
}

impl Opts {
    fn new() -> Self {
        Opts {
            duplicate_branch_op_tails: true,
            trace_on: false,
        }
    }
}

impl From<u8> for Op {
    fn from(repr: u8) -> Self {
        Op::from_u8(repr)
    }
}

impl From<Op> for u8 {
    fn from(repr: Op) -> Self {
        repr as u8
    }
}

impl Dispatchable<(VMRegs, Opts)> for Op {
    fn build_interp_entry(emit: &mut Emit, args: &(VMRegs, Opts)) {
        InterpContext::build_unpack_to_reg(emit, &args.0);
    }

    fn build_dispatch_case(self, emit: &mut Emit, args: &(VMRegs, Opts)) {
        Op::build_dispatch_case(self, emit, &args.0, &args.1);
    }

    fn build_dispatch_with_pc_offset(emit: &mut Emit, args: &(VMRegs, Opts), offset: i32) {
        build_dispatch_with_pc_offset(emit, &args.0, &args.1, offset);
    }
}

impl Op {
    fn from_u8(repr: u8) -> Self {
        unsafe { mem::transmute(repr) }
    }

    fn has_arg(self) -> bool {
        use self::Op::*;

        match self {
            LoadI8 | LoadL | BranchLt | Call | Ret => true,
            Halt | Add => false,
        }
    }

    unsafe fn display_ptr(ptr: isize, fmt: &mut fmt::Formatter) -> fmt::Result {
        let bptr = ptr as *const u8;
        let op = Op::from_u8(*bptr);
        if op.has_arg() {
            let oparg = *bptr.offset(1);
            write!(fmt, "{:?}({})", op, oparg)
        } else {
            write!(fmt, "{:?}", op)
        }
    }

    fn build_dispatch_case(self, emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
        use self::Op::*;

        fn push_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(&(vr.sp + (-8)), r)
                .sub(vr.sp, 8);
        }

        fn push_a(emit: &mut Emit, vr: &VMRegs, a: &Addr) {
            emit.mov(vr.scratch, a)
                .mov(&(vr.sp + (-8)), vr.scratch)
                .sub(vr.sp, 8);
        }

        fn pop_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(r, &Addr::B(vr.sp))
                .add(vr.sp, 8);
        }

        match self {
            LoadI8 => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            LoadL => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_a(emit, vr, &(vr.sp + vr.tmpl * 8));
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            BranchLt => {
                pop_r(emit, vr, vr.tmpr);
                pop_r(emit, vr, vr.tmpl);
                emit.cmp(vr.tmpl, vr.tmpr);

                if opts.duplicate_branch_op_tails {
                    let mut lt = Label::new();
                    emit.jl(&mut lt);
                    build_dispatch_skip_oparg(emit, vr, opts);
                    emit.bind(&mut lt)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl);
                    build_dispatch_skip_oparg(emit, vr, opts);
                } else {
                    let mut ge = Label::new();
                    emit.jge(&mut ge)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl)
                        .bind(&mut ge);
                    build_dispatch_skip_oparg(emit, vr, opts);
                }
            }
            Call => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .add(vr.pc, 2);

                push_r(emit, vr, vr.pc);
                emit.mov(vr.pc, &(vr.func_table + vr.tmpl * 8));
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Ret => {
                pop_r(emit, vr, vr.tmpl);
                emit.movsb(vr.tmpr, &(vr.pc + 1));
                pop_r(emit, vr, vr.pc);
                emit.lea(vr.sp, &(vr.sp + vr.tmpr * 8));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Halt => {
                pop_r(emit, vr, rax);
                emit.ret();
            }
            Add => {
                pop_r(emit, vr, vr.tmpr);
                emit.add(&Addr::B(vr.sp), vr.tmpr);
                build_dispatch_with_pc_offset(emit, vr, opts, 1);
            }
        }
    }

}

fn build_dispatch_with_pc_offset(emit: &mut Emit, vr: &VMRegs, opts: &Opts, offset: i32) {
    if offset == 0 {
        emit.movsb(vr.tmpl, &Addr::B(vr.pc));
    } else {
        emit.movsb(vr.tmpl, &(vr.pc + offset))
            .add(vr.pc, offset);
    }

    // Like PyPy's jit_merge_point
    if opts.trace_on {
        let rs = vr.regs();
        for r in &rs {
            emit.push(*r);
        }

        let mut moar_pops: Box<FnMut(&mut Emit)> = if rs.len() % 2 == 0 {
            // Stack alignment
            emit.push(rax);
            Box::new(|emit| { emit.pop(rax); })
        } else {
            Box::new(|_| ())
        };

        emit.mov(rsi, vr.pc)  // Since pc == rdi. XXX: hardcoded...
            .mov(rdi, vr.trace_ctx)
            .mov(rax, unsafe { mem::transmute::<_, i64>(TraceContext::record_unsafe) })
            .call(rax);

        moar_pops(emit);

        for r in rs.iter().rev() {
            emit.pop(*r);
        }
    }

    emit.jmp(&(vr.dispatch_table + vr.tmpl * 8));
}

fn build_dispatch_skip_oparg(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 2)
}

fn build_dispatch_correct_pc(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 0)
}

pub fn main(n: u8) {
    use self::Instr::*;
    use self::Op::*;

    let mut opts = Opts::new();
    if env::var("NO_DUP_BR_TAILS").is_ok() {
        opts.duplicate_branch_op_tails = false;
    };

    if env::var("TRACE_ON").is_ok() {
        opts.trace_on = true;
    };

    let (labels, jm) = build_interp(LAST_OP, &(VMRegs::new(), opts));

    let main_code = instr_to_bs(&[
        OpWithArg(LoadI8, n as i8),
        OpWithArg(Call, 0),
        OpOnly(Halt),
    ]);

    let id_code = instr_to_bs(&[
        OpWithArg(LoadI8, 100),
        //OpWithArg(Ret, 1),
        OpOnly(Halt),
    ]);

    let fibo_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, 2),
        OpWithArg(BranchLt, 17),

        // Recur case.
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, -1),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpWithArg(LoadL, 2),
        OpWithArg(LoadI8, -2),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpOnly(Add),
        OpWithArg(Ret, 1),

        // Base case.
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let func_table = [
        id_code.as_ptr(),
        fibo_code.as_ptr(),
    ];

    let trace_ctx = TraceContext::new();

    let stack = [0_isize; 1024];

    let res = unsafe {
        let pc = main_code.as_ptr() as isize;
        let lbl_ptr = labels.as_ptr() as isize;
        let func_table_ptr = func_table.as_ptr() as isize;
        let trace_ctx_ptr = trace_ctx.as_ptr() as isize;
        let stack_ptr = stack.as_ptr().offset(stack.len() as isize) as isize;
        let ictx = InterpContext {
            pc: pc,
            func_table: func_table_ptr,
            trace_ctx: trace_ctx_ptr,
            dispatch_table: lbl_ptr,
            sp: stack_ptr,
        };
        if env::var("BREAK").is_ok() {
            breakpoint();
        }
        jm.call_ptr_ptr(&ictx as *const _ as isize)
    };
    println!("res = {}", res);
    println!("trace = {}", trace_ctx);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use crate::sys;
use crate::Instance;
use crate::Media;
use crate::EventManager;
use libc::{c_void, c_uint};
use crate::enums::{State, Position};
use std::mem::transmute;

/// A LibVLC media player plays one media (usually in a custom drawable).
pub struct MediaPlayer {
    pub(crate) ptr: *mut sys::libvlc_media_player_t,
}

impl MediaPlayer {
    /// Create an empty Media Player object
    pub fn new(instance: &Instance) -> Option<MediaPlayer> {
        unsafe{
            let p = sys::libvlc_media_player_new(instance.ptr);

            if p.is_null() {
                return None;
            }
            Some(MediaPlayer{ptr: p})
        }
    }

    /// Set the media that will be used by the media_player. If any, previous md will be released.
    pub fn set_media(&self, md: &Media) {
        unsafe{ sys::libvlc_media_player_set_media(self.ptr, md.ptr) };
    }

    /// Get the media used by the media_player.
    pub fn get_media(&self) -> Option<Media> {
        let p = unsafe{ sys::libvlc_media_player_get_media(self.ptr) };
        if p.is_null() {
            None
        }else{
            Some(Media{ptr: p})
        }
    }

    /// Get the Event Manager from which the media player send event.
    pub fn event_manager<'a>(&'a self) -> EventManager<'a> {
        unsafe{
            let p = sys::libvlc_media_player_event_manager(self.ptr);
            assert!(!p.is_null());
            EventManager{ptr: p, _phantomdata: ::std::marker::PhantomData}
        }
    }

    /// is_playing
    pub fn is_playing(&self) -> bool {
        if unsafe{ sys::libvlc_media_player_is_playing(self.ptr) } == 0 {
            false
        }else{
            true
        }
    }

    /// Play
    pub fn play(&self) -> Result<(), ()> {
        if unsafe{ sys::libvlc_media_player_play(self.ptr) } == 0 {
            Ok(())
        }else{
            Err(())
        }
    }

    /// Pause or resume (no effect if there is no media)
    pub fn set_pause(&self, do_pause: bool) {
        unsafe{ sys::libvlc_media_player_set_pause(self.ptr, if do_pause {1} else {0}) };
    }

    /// Toggle pause (no effect if there is no media)
    pub fn pause(&self) {
        unsafe{ sys::libvlc_media_player_pause(self.ptr) };
    }

    /// Stop (no effect if there is no media)
    pub fn stop(&self) {
        unsafe{ sys::libvlc_media_player_stop(self.ptr) };
    }

    pub fn set_callbacks<F>(
        &self,
        play: F,
        pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
        resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
        flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
        drain: Option<Box<dyn Fn() + Send + 'static>>)
        where F: Fn(*const c_void, u32, i64) + Send + 'static,
    {
        let flag_pause = pause.is_some();
        let flag_resume = resume.is_some();
        let flag_flush = flush.is_some();
        let flag_drain = drain.is_some();

        let data = AudioCallbacksData {
            play: Box::new(play), pause: pause, resume: resume,
            flush: flush, drain: drain,
        };
        let data = Box::into_raw(Box::new(data));

        unsafe{
            sys::libvlc_audio_set_callbacks(
                self.ptr,
                Some(audio_cb_play),
                if flag_pause {Some(audio_cb_pause)} else {None},
                if flag_resume {Some(audio_cb_resume)} else {None},
                if flag_flush {Some(audio_cb_flush)} else {None},
                if flag_drain {Some(audio_cb_drain)} else {None},
                data as *mut c_void);
        }
    }

    /// Set the NSView handler where the media player should render its video output.
    pub fn set_nsobject(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_nsobject(self.ptr, drawable) };
    }

    /// Get the NSView handler previously set with set_nsobject().
    pub fn get_nsobject(&self) -> Option<*mut c_void> {
        let nso = unsafe{ sys::libvlc_media_player_get_nsobject(self.ptr) };
        if nso.is_null() { None }else{ Some(nso) }
    }

    /// Set an X Window System drawable where the media player should render its video output.
    pub fn set_xwindow(&self, drawable: u32) {
        unsafe{ sys::libvlc_media_player_set_xwindow(self.ptr, drawable) };
    }

    /// Get the X Window System window identifier previously set with set_xwindow().
    pub fn get_xwindow(&self) -> Option<u32> {
        let id = unsafe{ sys::libvlc_media_player_get_xwindow(self.ptr) };
        if id == 0 { None }else{ Some(id) }
    }

    /// Set a Win32/Win64 API window handle (HWND) where the media player should render its video output.
    /// If LibVLC was built without Win32/Win64 API output support, then this has no effects.
    pub fn set_hwnd(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_hwnd(self.ptr, drawable) };
    }

    /// Get the Windows API window handle (HWND) previously set with set_hwnd().
    pub fn get_hwnd(&self) -> Option<*mut c_void> {
        let hwnd = unsafe{ sys::libvlc_media_player_get_hwnd(self.ptr) };
        if hwnd.is_null() { None }else{ Some(hwnd) }
    }

    /// Get the current movie time (in ms).
    pub fn get_time(&self) -> Option<i64> {
        unsafe{
            let t = sys::libvlc_media_player_get_time(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Set the movie time (in ms).
    /// This has no effect if no media is being played. Not all formats and protocols support this.
    pub fn set_time(&self, time: i64) {
        unsafe{ sys::libvlc_media_player_set_time(self.ptr, time); }
    }

    /// Get movie position as percentage between 0.0 and 1.0.
    pub fn get_position(&self) -> Option<f32> {
        unsafe{
            let pos = sys::libvlc_media_player_get_position(self.ptr);
            if pos == -1f32 { None }else{ Some(pos) }
        }
    }

    /// Set movie position as percentage between 0.0 and 1.0.
    /// This has no effect if playback is not enabled. This might not work depending on the underlying input format and protocol.
    pub fn set_position(&self, pos: f32) {
        unsafe{ sys::libvlc_media_player_set_position(self.ptr, pos); }
    }

    /// Set movie chapter (if applicable).
    pub fn set_chapter(&self, chapter: i32) {
        unsafe{ sys::libvlc_media_player_set_chapter(self.ptr, chapter); }
    }

    /// Get movie chapter.
    pub fn get_chapter(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Get movie chapter count.
    pub fn chapter_count(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Is the player able to play.
    pub fn will_play(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_will_play(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Get title chapter count.
    pub fn chapter_count_for_title(&self, title: i32) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count_for_title(self.ptr, title);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Set movie title.
    pub fn set_title(&self, title: i32) {
        unsafe{ sys::libvlc_media_player_set_title(self.ptr, title); }
    }

    /// Get movie title.
    pub fn get_title(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Get movie title count.
    pub fn title_count(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title_count(self.ptr);
            if t == -1 { Some(t) } else { None }
        }
    }

    /// Set previous chapter (if applicable)
    pub fn previous_chapter(&self) {
        unsafe{ sys::libvlc_media_player_previous_chapter(self.ptr); }
    }

    /// Set next chapter (if applicable)
    pub fn next_chapter(&self) {
        unsafe{ sys::libvlc_media_player_next_chapter(self.ptr); }
    }

    /// Get the requested movie play rate.
    pub fn get_rate(&self) -> f32 {
        unsafe{ sys::libvlc_media_player_get_rate(self.ptr) }
    }

    /// Set movie play rate.
    pub fn set_rate(&self, rate: f32) -> Result<(),()> {
        unsafe{
            if sys::libvlc_media_player_set_rate(self.ptr, rate) == -1 {
                Err(())
            }else{
                Ok(())
            }
        }
    }

    /// Get current movie state.
    pub fn state(&self) -> State {
        unsafe{ sys::libvlc_media_player_get_state(self.ptr) }
    }

    /// How many video outputs does this media player have?
    pub fn has_vout(&self) -> u32 {
        unsafe{ sys::libvlc_media_player_has_vout(self.ptr) }
    }

    /// Is this media player seekable?
    pub fn is_seekable(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_is_seekable(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Can this media player be paused?
    pub fn can_pause(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_can_pause(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Check if the current program is scrambled.
    pub fn program_scrambled(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_program_scrambled(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Display the next frame (if supported)
    pub fn next_frame(&self) {
        unsafe{ sys::libvlc_media_player_next_frame(self.ptr); }
    }

    /// Navigate through DVD Menu.
    pub fn navigate(&self, navigate: u32) {
        unsafe{ sys::libvlc_media_player_navigate(self.ptr, navigate); }
    }

    /// Set if, and how, the video title will be shown when media is played.
    pub fn set_video_title_display(&self, position: Position, timeout: u32) {
        unsafe{ sys::libvlc_media_player_set_video_title_display(self.ptr, position, timeout); }
    }

    /// Returns raw pointer
    pub fn raw(&self) -> *mut sys::libvlc_media_player_t {
        self.ptr
    }
}

impl Drop for MediaPlayer {
    fn drop(&mut self) {
        unsafe{ sys::libvlc_media_player_release(self.ptr) };
    }
}

// For audio_set_callbacks
struct AudioCallbacksData {
    play: Box<dyn Fn(*const c_void, u32, i64) + Send + 'static>,
    pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
    resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
    flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
    drain: Option<Box<dyn Fn() + Send + 'static>>,
}

unsafe extern "C" fn audio_cb_play(
    data: *mut c_void, samples: *const c_void, count: c_uint, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.play)(samples, count, pts);

}

unsafe extern "C" fn audio_cb_pause(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.pause.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_resume(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.resume.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_flush(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.flush.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_drain(data: *mut c_void) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.drain.as_ref().unwrap())();
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TrackDescription {
    pub id: i32,
    pub name: Option<String>,
}

<commit_msg>media_player: fix whitespace<commit_after>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use crate::sys;
use crate::Instance;
use crate::Media;
use crate::EventManager;
use libc::{c_void, c_uint};
use crate::enums::{State, Position};
use std::mem::transmute;

/// A LibVLC media player plays one media (usually in a custom drawable).
pub struct MediaPlayer {
    pub(crate) ptr: *mut sys::libvlc_media_player_t,
}

impl MediaPlayer {
    /// Create an empty Media Player object
    pub fn new(instance: &Instance) -> Option<MediaPlayer> {
        unsafe{
            let p = sys::libvlc_media_player_new(instance.ptr);

            if p.is_null() {
                return None;
            }
            Some(MediaPlayer{ptr: p})
        }
    }

    /// Set the media that will be used by the media_player. If any, previous md will be released.
    pub fn set_media(&self, md: &Media) {
        unsafe{ sys::libvlc_media_player_set_media(self.ptr, md.ptr) };
    }

    /// Get the media used by the media_player.
    pub fn get_media(&self) -> Option<Media> {
        let p = unsafe{ sys::libvlc_media_player_get_media(self.ptr) };
        if p.is_null() {
            None
        }else{
            Some(Media{ptr: p})
        }
    }

    /// Get the Event Manager from which the media player send event.
    pub fn event_manager<'a>(&'a self) -> EventManager<'a> {
        unsafe{
            let p = sys::libvlc_media_player_event_manager(self.ptr);
            assert!(!p.is_null());
            EventManager{ptr: p, _phantomdata: ::std::marker::PhantomData}
        }
    }

    /// is_playing
    pub fn is_playing(&self) -> bool {
        if unsafe{ sys::libvlc_media_player_is_playing(self.ptr) } == 0 {
            false
        }else{
            true
        }
    }

    /// Play
    pub fn play(&self) -> Result<(), ()> {
        if unsafe{ sys::libvlc_media_player_play(self.ptr) } == 0 {
            Ok(())
        }else{
            Err(())
        }
    }

    /// Pause or resume (no effect if there is no media)
    pub fn set_pause(&self, do_pause: bool) {
        unsafe{ sys::libvlc_media_player_set_pause(self.ptr, if do_pause {1} else {0}) };
    }

    /// Toggle pause (no effect if there is no media)
    pub fn pause(&self) {
        unsafe{ sys::libvlc_media_player_pause(self.ptr) };
    }

    /// Stop (no effect if there is no media)
    pub fn stop(&self) {
        unsafe{ sys::libvlc_media_player_stop(self.ptr) };
    }

    pub fn set_callbacks<F>(
        &self,
        play: F,
        pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
        resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
        flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
        drain: Option<Box<dyn Fn() + Send + 'static>>)
        where F: Fn(*const c_void, u32, i64) + Send + 'static,
    {
        let flag_pause = pause.is_some();
        let flag_resume = resume.is_some();
        let flag_flush = flush.is_some();
        let flag_drain = drain.is_some();

        let data = AudioCallbacksData {
            play: Box::new(play), pause: pause, resume: resume,
            flush: flush, drain: drain,
        };
        let data = Box::into_raw(Box::new(data));

        unsafe{
            sys::libvlc_audio_set_callbacks(
                self.ptr,
                Some(audio_cb_play),
                if flag_pause {Some(audio_cb_pause)} else {None},
                if flag_resume {Some(audio_cb_resume)} else {None},
                if flag_flush {Some(audio_cb_flush)} else {None},
                if flag_drain {Some(audio_cb_drain)} else {None},
                data as *mut c_void);
        }
    }

    /// Set the NSView handler where the media player should render its video output.
    pub fn set_nsobject(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_nsobject(self.ptr, drawable) };
    }

    /// Get the NSView handler previously set with set_nsobject().
    pub fn get_nsobject(&self) -> Option<*mut c_void> {
        let nso = unsafe{ sys::libvlc_media_player_get_nsobject(self.ptr) };
        if nso.is_null() { None }else{ Some(nso) }
    }

    /// Set an X Window System drawable where the media player should render its video output.
    pub fn set_xwindow(&self, drawable: u32) {
        unsafe{ sys::libvlc_media_player_set_xwindow(self.ptr, drawable) };
    }

    /// Get the X Window System window identifier previously set with set_xwindow().
    pub fn get_xwindow(&self) -> Option<u32> {
        let id = unsafe{ sys::libvlc_media_player_get_xwindow(self.ptr) };
        if id == 0 { None }else{ Some(id) }
    }

    /// Set a Win32/Win64 API window handle (HWND) where the media player should render its video output.
    /// If LibVLC was built without Win32/Win64 API output support, then this has no effects.
    pub fn set_hwnd(&self, drawable: *mut c_void) {
        unsafe{ sys::libvlc_media_player_set_hwnd(self.ptr, drawable) };
    }

    /// Get the Windows API window handle (HWND) previously set with set_hwnd().
    pub fn get_hwnd(&self) -> Option<*mut c_void> {
        let hwnd = unsafe{ sys::libvlc_media_player_get_hwnd(self.ptr) };
        if hwnd.is_null() { None }else{ Some(hwnd) }
    }

    /// Get the current movie time (in ms).
    pub fn get_time(&self) -> Option<i64> {
        unsafe{
            let t = sys::libvlc_media_player_get_time(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Set the movie time (in ms).
    /// This has no effect if no media is being played. Not all formats and protocols support this.
    pub fn set_time(&self, time: i64) {
        unsafe{ sys::libvlc_media_player_set_time(self.ptr, time); }
    }

    /// Get movie position as percentage between 0.0 and 1.0.
    pub fn get_position(&self) -> Option<f32> {
        unsafe{
            let pos = sys::libvlc_media_player_get_position(self.ptr);
            if pos == -1f32 { None }else{ Some(pos) }
        }
    }

    /// Set movie position as percentage between 0.0 and 1.0.
    /// This has no effect if playback is not enabled. This might not work depending on the underlying input format and protocol.
    pub fn set_position(&self, pos: f32) {
        unsafe{ sys::libvlc_media_player_set_position(self.ptr, pos); }
    }

    /// Set movie chapter (if applicable).
    pub fn set_chapter(&self, chapter: i32) {
        unsafe{ sys::libvlc_media_player_set_chapter(self.ptr, chapter); }
    }

    /// Get movie chapter.
    pub fn get_chapter(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Get movie chapter count.
    pub fn chapter_count(&self) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count(self.ptr);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Is the player able to play.
    pub fn will_play(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_will_play(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Get title chapter count.
    pub fn chapter_count_for_title(&self, title: i32) -> Option<i32> {
        unsafe{
            let c = sys::libvlc_media_player_get_chapter_count_for_title(self.ptr, title);
            if c == -1 { None }else{ Some(c) }
        }
    }

    /// Set movie title.
    pub fn set_title(&self, title: i32) {
        unsafe{ sys::libvlc_media_player_set_title(self.ptr, title); }
    }

    /// Get movie title.
    pub fn get_title(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title(self.ptr);
            if t == -1 { None }else{ Some(t) }
        }
    }

    /// Get movie title count.
    pub fn title_count(&self) -> Option<i32> {
        unsafe{
            let t = sys::libvlc_media_player_get_title_count(self.ptr);
            if t == -1 { Some(t) } else { None }
        }
    }

    /// Set previous chapter (if applicable)
    pub fn previous_chapter(&self) {
        unsafe{ sys::libvlc_media_player_previous_chapter(self.ptr); }
    }

    /// Set next chapter (if applicable)
    pub fn next_chapter(&self) {
        unsafe{ sys::libvlc_media_player_next_chapter(self.ptr); }
    }

    /// Get the requested movie play rate.
    pub fn get_rate(&self) -> f32 {
        unsafe{ sys::libvlc_media_player_get_rate(self.ptr) }
    }

    /// Set movie play rate.
    pub fn set_rate(&self, rate: f32) -> Result<(),()> {
        unsafe{
            if sys::libvlc_media_player_set_rate(self.ptr, rate) == -1 {
                Err(())
            }else{
                Ok(())
            }
        }
    }

    /// Get current movie state.
    pub fn state(&self) -> State {
        unsafe{ sys::libvlc_media_player_get_state(self.ptr) }
    }

    /// How many video outputs does this media player have?
    pub fn has_vout(&self) -> u32 {
        unsafe{ sys::libvlc_media_player_has_vout(self.ptr) }
    }

    /// Is this media player seekable?
    pub fn is_seekable(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_is_seekable(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Can this media player be paused?
    pub fn can_pause(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_can_pause(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Check if the current program is scrambled.
    pub fn program_scrambled(&self) -> bool {
        unsafe{
            let b = sys::libvlc_media_player_program_scrambled(self.ptr);
            if b == 0 { false }else{ true }
        }
    }

    /// Display the next frame (if supported)
    pub fn next_frame(&self) {
        unsafe{ sys::libvlc_media_player_next_frame(self.ptr); }
    }

    /// Navigate through DVD Menu.
    pub fn navigate(&self, navigate: u32) {
        unsafe{ sys::libvlc_media_player_navigate(self.ptr, navigate); }
    }

    /// Set if, and how, the video title will be shown when media is played.
    pub fn set_video_title_display(&self, position: Position, timeout: u32) {
        unsafe{ sys::libvlc_media_player_set_video_title_display(self.ptr, position, timeout); }
    }

    /// Returns raw pointer
    pub fn raw(&self) -> *mut sys::libvlc_media_player_t {
        self.ptr
    }
}

impl Drop for MediaPlayer {
    fn drop(&mut self) {
        unsafe{ sys::libvlc_media_player_release(self.ptr) };
    }
}

// For audio_set_callbacks
struct AudioCallbacksData {
    play: Box<dyn Fn(*const c_void, u32, i64) + Send + 'static>,
    pause: Option<Box<dyn Fn(i64) + Send + 'static>>,
    resume: Option<Box<dyn Fn(i64) + Send + 'static>>,
    flush: Option<Box<dyn Fn(i64) + Send + 'static>>,
    drain: Option<Box<dyn Fn() + Send + 'static>>,
}

unsafe extern "C" fn audio_cb_play(
    data: *mut c_void, samples: *const c_void, count: c_uint, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.play)(samples, count, pts);

}

unsafe extern "C" fn audio_cb_pause(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.pause.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_resume(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.resume.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_flush(data: *mut c_void, pts: i64) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.flush.as_ref().unwrap())(pts);
}

unsafe extern "C" fn audio_cb_drain(data: *mut c_void) {
    let data: &AudioCallbacksData = transmute(data as *mut AudioCallbacksData);
    (data.drain.as_ref().unwrap())();
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TrackDescription {
    pub id: i32,
    pub name: Option<String>,
}

<|endoftext|>


<commit_before>use core::*;
use opengl_graphics::*;
use graphics::*;

/// A player
pub struct Player {
  pos: Vec2<i64>,
  dir: Dir,
  trans: f64,
  frame: i16,
  last_move: f64,
}

impl Position for Player {
  fn get_pos(&self) -> Vec2<i64> {
    self.pos
  }
  fn set_pos(&mut self, new_pos: Vec2<i64>) {
    self.pos = new_pos;
  }
}

impl Move for Player {
  fn get_dir(&self) -> Dir {
    self.dir
  }
  fn set_dir(&mut self, new_dir: Dir) {
    self.dir = new_dir;
  }
  fn is_moving(&self) -> bool {
    // TODO: Code here.
    unimplemented!()
  }
  fn can_move(&self) -> bool {
    // TODO: Check if the way is blocked, using the cache.
    unimplemented!()
  }
  fn get_last_move(&self) -> f64 {
    self.last_move
  }
  fn set_last_move(&mut self, new: &f64) {
    self.last_move = *new;
  }
  fn get_speed(&self) -> f64 {
    1.0
  }
  fn get_trans_state(&self) -> f64 {
    self.trans
  }
  fn get_animation_frame(&self) -> i16 {
    self.frame
  }
}

impl Sprite for Player {
  fn get_sprite(&self) -> &Texture {
    unimplemented!();
    // TODO: Sprite here
  }
  fn get_width(&self) -> i16 {
    1
  }
  fn get_height(&self) -> i16 {
    1
  }
  fn get_opacity(&self) -> f64 {
    1.0
  }
  fn draw(&self, c: &Context, gl: &mut GlGraphics) {
     unimplemented!()
  }
}

impl Matter for Player {}

impl Entity for Player {
  fn id(&self) -> Id {
    Id(0) // NOTE: Player's ID is always 0
  }
  fn is_solid(&self, x: i16, y: i16) -> bool {
    false // TODO: Should it be solid?
  }
  fn update(&mut self, dt: f64) {
    self.move_reg();
  }
}
<commit_msg>Add multiple direction, TODO: Implement new trait methods for Player (maybe even consider rewriting the whole player.rs)<commit_after>use core::*;
use opengl_graphics::*;
use graphics::*;

/// A player
pub struct Player {
  pos: Vec2<i64>,
  dir: Dir,
  trans: f64,
  frame: i16,
  last_move: f64,
}

impl Position for Player {
  fn get_pos(&self) -> Vec2<i64> {
    self.pos
  }
  fn set_pos(&mut self, new_pos: Vec2<i64>) {
    self.pos = new_pos;
  }
}

// TODO: Implement new trait methods for Player
unimplemented!();
impl Move for Player {
  fn get_dir(&self) -> Dir {
    self.dir
  }
  fn set_dir(&mut self, new_dir: Dir) {
    self.dir = new_dir;
  }
  fn is_moving(&self) -> bool {
    // TODO: Code here.
    unimplemented!()
  }
  fn can_move(&self) -> bool {
    // TODO: Check if the way is blocked, using the cache.
    unimplemented!()
  }
  fn get_last_move(&self) -> f64 {
    self.last_move
  }
  fn set_last_move(&mut self, new: &f64) {
    self.last_move = *new;
  }
  fn get_speed(&self) -> f64 {
    1.0
  }
  fn get_trans_state(&self) -> f64 {
    self.trans
  }
  fn get_animation_frame(&self) -> i16 {
    self.frame
  }
}

impl Sprite for Player {
  fn get_sprite(&self) -> &Texture {
    unimplemented!();
    // TODO: Sprite here
  }
  fn get_width(&self) -> i16 {
    1
  }
  fn get_height(&self) -> i16 {
    1
  }
  fn get_opacity(&self) -> f64 {
    1.0
  }
  fn draw(&self, c: &Context, gl: &mut GlGraphics) {
     unimplemented!()
  }
}

impl Matter for Player {}

impl Entity for Player {
  fn id(&self) -> Id {
    Id(0) // NOTE: Player's ID is always 0
  }
  fn is_solid(&self, x: i16, y: i16) -> bool {
    false // TODO: Should it be solid?
  }
  fn update(&mut self, dt: f64) {
    self.move_reg();
  }
}
<|endoftext|>