<commit_before>#[doc(hidden)]
macro_rules! link {
    (
        $(
            extern "C" {
                pub fn $name:ident($($pname:ident: $pty:ty),* $(,)?) $(-> $ret:ty)*;
            }
        )+
    ) => (
        use lazy_static::lazy_static;
        use libloading;
        use std::path::PathBuf;
        use std::sync::Arc;
        use std::sync::RwLock;

        // Wrap the loaded functions.
        pub(crate) struct SharedLibrary {
            library: libloading::Library,
            path: PathBuf,
            pub functions: Functions,
        }
        impl SharedLibrary {
            fn new(library: libloading::Library, path: PathBuf) -> Self {
                Self {
                    library,
                    path,
                    functions: Functions::default(),
                }
            }
        }

        // `LIBRARY` holds the shared library reference.
        lazy_static!{
            static ref LIBRARY: RwLock<Option<Arc<SharedLibrary>>> = RwLock::new(None);
        }

        // Helper function for accessing the thread-local version of the library.
        fn with_library<T, F>(f: F) -> Option<T>
        where
            F: FnOnce(&SharedLibrary) -> T,
        {
            match LIBRARY.read().unwrap().as_ref() {
                Some(library) => Some(f(&library)),
                _ => None,
            }
        }

        // The set of functions loaded dynamically.
        #[derive(Default)]
        pub(crate) struct Functions {
            $(
                pub $name: Option<unsafe extern fn($($pname: $pty), *) $(-> $ret)*>,
            )+
        }

        // Provide functions to load each name from the shared library into the `SharedLibrary`
        // struct.
        mod load {
            $(
                pub(crate) fn $name(library: &mut super::SharedLibrary) {
                    let symbol = unsafe { library.library.get(stringify!($name).as_bytes()) }.ok();
                    library.functions.$name = match symbol {
                        Some(s) => *s,
                        None => None,
                    };
                }
            )+
        }

        /// Load all of the function definitions from a shared library.
        pub fn load() -> Result<(), String> {
            match crate::library::find() {
                None => Err("Unable to find the `libtensorflow` library to load".into()),
                Some(path) => load_from(path),
            }
        }
        fn load_from(path: PathBuf) -> Result<(), String> {
            let lib_path = SharedLibrary::load(path)?;
            let library = Arc::new(lib_path);
            *LIBRARY.write().unwrap() = Some(library);
            Ok(())
        }
        impl SharedLibrary {
            fn load(path: PathBuf) -> Result<SharedLibrary, String> {
                unsafe {
                    let library = libloading::Library::new(&path).map_err(|e| {
                        format!(
                            "the shared library at {} could not be opened: {}",
                            path.display(),
                            e,
                        )
                    })?;

                    let mut library = SharedLibrary::new(library, path);
                    $(load::$name(&mut library);)+
                    Ok(library)
                }
            }
        }
        // For each loaded function, we redefine them to proxy their call through the SharedLibrary
        // on the local thread and into the loaded shared library implementation.
        $(
            pub unsafe fn $name($($pname: $pty), *) $(-> $ret)* {
                let f = with_library(|l| {
                    l.functions.$name.expect(concat!(
                        "`libtensorflow` function not loaded: `",
                        stringify!($name)
                    ))
                }).expect("an `libtensorflow` shared library is not loaded on this thread");
                f($($pname), *)
            }
        )+
    )
}
<commit_msg>Undoing previous and adding the actual fix<commit_after>#[doc(hidden)]
macro_rules! link {
    (
        $(
            extern "C" {
                pub fn $name:ident($($pname:ident: $pty:ty),* $(,)?) $(-> $ret:ty)*;
            }
        )+
    ) => (
        use lazy_static::lazy_static;
        use libloading;
        use std::path::PathBuf;
        use std::sync::Arc;
        use std::sync::RwLock;

        // Wrap the loaded functions.
        pub(crate) struct SharedLibrary {
            library: libloading::Library,
            path: PathBuf,
            pub functions: Functions,
        }
        impl SharedLibrary {
            fn new(library: libloading::Library, path: PathBuf) -> Self {
                Self {
                    library,
                    path,
                    functions: Functions::default(),
                }
            }
        }

        // `LIBRARY` holds the shared library reference.
        lazy_static!{
            static ref LIBRARY: RwLock<Option<Arc<SharedLibrary>>> = RwLock::new(None);
        }

        // Helper function for accessing the thread-local version of the library.
        fn with_library<T, F>(f: F) -> Option<T>
        where
            F: FnOnce(&SharedLibrary) -> T,
        {
            match LIBRARY.read().unwrap().as_ref() {
                Some(library) => Some(f(&library)),
                _ => None,
            }
        }

        // The set of functions loaded dynamically.
        #[derive(Default)]
        pub(crate) struct Functions {
            $(
                pub $name: Option<unsafe extern fn($($pname: $pty), *) $(-> $ret)*>,
            )+
        }

        // Provide functions to load each name from the shared library into the `SharedLibrary`
        // struct.
        mod load {
            $(
                pub(crate) fn $name(library: &mut super::SharedLibrary) {
                    let symbol = unsafe { library.library.get(stringify!($name).as_bytes()) }.ok();
                    library.functions.$name = match symbol {
                        Some(s) => *s,
                        None => None,
                    };
                }
            )+
        }

        /// Load all of the function definitions from a shared library.
        pub fn load() -> Result<(), String> {
            match crate::library::find() {
                None => Err("Unable to find the `libtensorflow` library to load".into()),
                Some(path) => load_from(path),
            }
        }
        fn load_from(path: PathBuf) -> Result<(), String> {
            let library = Arc::new(SharedLibrary::load(path)?);

            let mut static_lib = LIBRARY.write().map_err(|e| {
                format!( "Failed to acquire global lock for TensorFlow library {}",e)
            }).unwrap();

            *static_lib = Some(library);
            Ok(())
        }
        impl SharedLibrary {
            fn load(path: PathBuf) -> Result<SharedLibrary, String> {
                unsafe {
                    let library = libloading::Library::new(&path).map_err(|e| {
                        format!(
                            "the shared library at {} could not be opened: {}",
                            path.display(),
                            e,
                        )
                    });

                    let mut library = SharedLibrary::new(library?, path);
                    $(load::$name(&mut library);)+
                    Ok(library)
                }
            }
        }
        // For each loaded function, we redefine them to proxy their call through the SharedLibrary
        // on the local thread and into the loaded shared library implementation.
        $(
            pub unsafe fn $name($($pname: $pty), *) $(-> $ret)* {
                let f = with_library(|l| {
                    l.functions.$name.expect(concat!(
                        "`libtensorflow` function not loaded: `",
                        stringify!($name)
                    ))
                }).expect("an `libtensorflow` shared library is not loaded on this thread");
                f($($pname), *)
            }
        )+
    )
}
<|endoftext|>


<commit_before>use dicom::core::smallvec;
use dicom::{core::dicom_value, dictionary_std::tags};
use dicom::{
    core::{DataElement, PrimitiveValue, VR},
    encoding::transfer_syntax,
    object::{mem::InMemDicomObject, open_file, StandardDataDictionary},
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_ul::pdu::Pdu;
use dicom_ul::{
    association::ClientAssociationOptions,
    pdu::{PDataValue, PDataValueType},
};
use smallvec::smallvec;
use std::{io::Write, path::PathBuf};
use structopt::StructOpt;
use transfer_syntax::TransferSyntaxIndex;

/// DICOM C-STORE SCU
#[derive(Debug, StructOpt)]
struct App {
    /// socket address to STORE SCP (example: "127.0.0.1:104")
    addr: String,
    /// the DICOM file to store
    file: PathBuf,
    /// verbose mode
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
    /// the C-STORE message ID
    #[structopt(short = "m", long = "message-id", default_value = "1")]
    message_id: u16,
    /// the calling AE title
    #[structopt(long = "calling-ae-title", default_value = "ECHOSCU")]
    calling_ae_title: String,
    /// the called AE title
    #[structopt(long = "called-ae-title", default_value = "ANY-SCP")]
    called_ae_title: String,
    /// the maximum PDU length
    #[structopt(long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        addr,
        file,
        verbose,
        message_id,
        calling_ae_title,
        called_ae_title,
        max_pdu_length,
    } = App::from_args();

    if verbose {
        println!("Opening file '{}'...", file.display());
    }

    let dicom_file = open_file(file)?;

    let meta = dicom_file.meta();

    let storage_sop_class_uid = &meta.media_storage_sop_class_uid;
    let storage_sop_instance_uid = &meta.media_storage_sop_instance_uid;
    let transfer_syntax = &meta.transfer_syntax;

    if verbose {
        println!("Establishing association with '{}'...", &addr);
    }

    let mut scu = ClientAssociationOptions::new()
        .with_abstract_syntax(storage_sop_class_uid.to_string())
        .with_transfer_syntax(transfer_syntax.to_string())
        .calling_ae_title(calling_ae_title)
        .called_ae_title(called_ae_title)
        .max_pdu_length(max_pdu_length)
        .establish(addr)?;

    if verbose {
        println!("Association established");
    }
    let ts = TransferSyntaxRegistry
        .get(&transfer_syntax)
        .expect("Poorly negotiated transfer syntax");

    if verbose {
        println!("Transfer Syntax: {}", ts.name());
    }

    let cmd = store_req_command(
        &storage_sop_class_uid,
        &storage_sop_instance_uid,
        message_id,
    );

    let mut cmd_data = Vec::with_capacity(128);
    cmd.write_dataset_with_ts(
        &mut cmd_data,
        &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
    )?;

    // !!! ensure that the negotiated transfer syntax is used

    let mut object_data = Vec::with_capacity(1024);
    dicom_file.write_dataset_with_ts(&mut object_data, &ts)?;

    let nbytes = cmd_data.len() + object_data.len();

    if verbose {
        println!("Sending payload (~ {} Kb)...", nbytes / 1024);
    }

    let pc_selected = scu
        .presentation_contexts()
        .first()
        .ok_or("No presentation context accepted")?
        .clone();

    if nbytes < max_pdu_length as usize - 100 {
        let pdu = Pdu::PData {
            data: vec![
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Command,
                    is_last: true,
                    data: cmd_data,
                },
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Data,
                    is_last: true,
                    data: object_data,
                },
            ],
        };

        scu.send(&pdu)?;
    } else {
        let pdu = Pdu::PData {
            data: vec![PDataValue {
                presentation_context_id: pc_selected.id,
                value_type: PDataValueType::Command,
                is_last: true,
                data: cmd_data,
            }],
        };

        scu.send(&pdu)?;

        scu.send_pdata(pc_selected.id).write_all(&object_data)?;
    }

    if verbose {
        println!("Awaiting response...");
    }

    let rsp_pdu = scu.receive()?;

    match rsp_pdu {
        Pdu::PData { data } => {
            let data_value = &data[0];

            let cmd_obj = InMemDicomObject::read_dataset_with_ts(
                &data_value.data[..],
                &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
            )?;
            if verbose {
                println!("Response: {:?}", cmd_obj);
            }
            let status = cmd_obj.element(tags::STATUS)?.to_int::<u16>()?;
            if status == 0 {
                println!("Sucessfully stored instance `{}`", storage_sop_instance_uid);
            } else {
                println!(
                    "Failed to store instance '{}' (status code {})",
                    storage_sop_instance_uid, status
                );
            }

            scu.release()?;
        }

        pdu @ Pdu::Unknown { .. }
        | pdu @ Pdu::AssociationRQ { .. }
        | pdu @ Pdu::AssociationAC { .. }
        | pdu @ Pdu::AssociationRJ { .. }
        | pdu @ Pdu::ReleaseRQ
        | pdu @ Pdu::ReleaseRP
        | pdu @ Pdu::AbortRQ { .. } => {
            eprintln!("Unexpected SCP response: {:?}", pdu);
            std::process::exit(-2);
        }
    }

    Ok(())
}

fn store_req_command(
    storage_sop_class_uid: &str,
    storage_sop_instance_uid: &str,
    message_id: u16,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        tags::COMMAND_GROUP_LENGTH,
        VR::UL,
        PrimitiveValue::from(0),
    ));

    // SOP Class UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_CLASS_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_class_uid),
    ));

    // command field
    obj.put(DataElement::new(
        tags::COMMAND_FIELD,
        VR::US,
        dicom_value!(U16, [0x0001]),
    ));

    // message ID
    obj.put(DataElement::new(
        tags::MESSAGE_ID,
        VR::US,
        dicom_value!(U16, [message_id]),
    ));

    //priority
    obj.put(DataElement::new(
        tags::PRIORITY,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // data set type
    obj.put(DataElement::new(
        tags::COMMAND_DATA_SET_TYPE,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // affected SOP Instance UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_INSTANCE_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_instance_uid),
    ));

    obj
}
<commit_msg>[storescu] change default calling AE title<commit_after>use dicom::core::smallvec;
use dicom::{core::dicom_value, dictionary_std::tags};
use dicom::{
    core::{DataElement, PrimitiveValue, VR},
    encoding::transfer_syntax,
    object::{mem::InMemDicomObject, open_file, StandardDataDictionary},
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_ul::pdu::Pdu;
use dicom_ul::{
    association::ClientAssociationOptions,
    pdu::{PDataValue, PDataValueType},
};
use smallvec::smallvec;
use std::{io::Write, path::PathBuf};
use structopt::StructOpt;
use transfer_syntax::TransferSyntaxIndex;

/// DICOM C-STORE SCU
#[derive(Debug, StructOpt)]
struct App {
    /// socket address to STORE SCP (example: "127.0.0.1:104")
    addr: String,
    /// the DICOM file to store
    file: PathBuf,
    /// verbose mode
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
    /// the C-STORE message ID
    #[structopt(short = "m", long = "message-id", default_value = "1")]
    message_id: u16,
    /// the calling AE title
    #[structopt(long = "calling-ae-title", default_value = "STORE-SCU")]
    calling_ae_title: String,
    /// the called AE title
    #[structopt(long = "called-ae-title", default_value = "ANY-SCP")]
    called_ae_title: String,
    /// the maximum PDU length
    #[structopt(long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        addr,
        file,
        verbose,
        message_id,
        calling_ae_title,
        called_ae_title,
        max_pdu_length,
    } = App::from_args();

    if verbose {
        println!("Opening file '{}'...", file.display());
    }

    let dicom_file = open_file(file)?;

    let meta = dicom_file.meta();

    let storage_sop_class_uid = &meta.media_storage_sop_class_uid;
    let storage_sop_instance_uid = &meta.media_storage_sop_instance_uid;
    let transfer_syntax = &meta.transfer_syntax;

    if verbose {
        println!("Establishing association with '{}'...", &addr);
    }

    let mut scu = ClientAssociationOptions::new()
        .with_abstract_syntax(storage_sop_class_uid.to_string())
        .with_transfer_syntax(transfer_syntax.to_string())
        .calling_ae_title(calling_ae_title)
        .called_ae_title(called_ae_title)
        .max_pdu_length(max_pdu_length)
        .establish(addr)?;

    if verbose {
        println!("Association established");
    }
    let ts = TransferSyntaxRegistry
        .get(&transfer_syntax)
        .expect("Poorly negotiated transfer syntax");

    if verbose {
        println!("Transfer Syntax: {}", ts.name());
    }

    let cmd = store_req_command(
        &storage_sop_class_uid,
        &storage_sop_instance_uid,
        message_id,
    );

    let mut cmd_data = Vec::with_capacity(128);
    cmd.write_dataset_with_ts(
        &mut cmd_data,
        &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
    )?;

    // !!! ensure that the negotiated transfer syntax is used

    let mut object_data = Vec::with_capacity(1024);
    dicom_file.write_dataset_with_ts(&mut object_data, &ts)?;

    let nbytes = cmd_data.len() + object_data.len();

    if verbose {
        println!("Sending payload (~ {} Kb)...", nbytes / 1024);
    }

    let pc_selected = scu
        .presentation_contexts()
        .first()
        .ok_or("No presentation context accepted")?
        .clone();

    if nbytes < max_pdu_length as usize - 100 {
        let pdu = Pdu::PData {
            data: vec![
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Command,
                    is_last: true,
                    data: cmd_data,
                },
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Data,
                    is_last: true,
                    data: object_data,
                },
            ],
        };

        scu.send(&pdu)?;
    } else {
        let pdu = Pdu::PData {
            data: vec![PDataValue {
                presentation_context_id: pc_selected.id,
                value_type: PDataValueType::Command,
                is_last: true,
                data: cmd_data,
            }],
        };

        scu.send(&pdu)?;

        scu.send_pdata(pc_selected.id).write_all(&object_data)?;
    }

    if verbose {
        println!("Awaiting response...");
    }

    let rsp_pdu = scu.receive()?;

    match rsp_pdu {
        Pdu::PData { data } => {
            let data_value = &data[0];

            let cmd_obj = InMemDicomObject::read_dataset_with_ts(
                &data_value.data[..],
                &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
            )?;
            if verbose {
                println!("Response: {:?}", cmd_obj);
            }
            let status = cmd_obj.element(tags::STATUS)?.to_int::<u16>()?;
            if status == 0 {
                println!("Sucessfully stored instance `{}`", storage_sop_instance_uid);
            } else {
                println!(
                    "Failed to store instance '{}' (status code {})",
                    storage_sop_instance_uid, status
                );
            }

            scu.release()?;
        }

        pdu @ Pdu::Unknown { .. }
        | pdu @ Pdu::AssociationRQ { .. }
        | pdu @ Pdu::AssociationAC { .. }
        | pdu @ Pdu::AssociationRJ { .. }
        | pdu @ Pdu::ReleaseRQ
        | pdu @ Pdu::ReleaseRP
        | pdu @ Pdu::AbortRQ { .. } => {
            eprintln!("Unexpected SCP response: {:?}", pdu);
            std::process::exit(-2);
        }
    }

    Ok(())
}

fn store_req_command(
    storage_sop_class_uid: &str,
    storage_sop_instance_uid: &str,
    message_id: u16,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        tags::COMMAND_GROUP_LENGTH,
        VR::UL,
        PrimitiveValue::from(0),
    ));

    // SOP Class UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_CLASS_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_class_uid),
    ));

    // command field
    obj.put(DataElement::new(
        tags::COMMAND_FIELD,
        VR::US,
        dicom_value!(U16, [0x0001]),
    ));

    // message ID
    obj.put(DataElement::new(
        tags::MESSAGE_ID,
        VR::US,
        dicom_value!(U16, [message_id]),
    ));

    //priority
    obj.put(DataElement::new(
        tags::PRIORITY,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // data set type
    obj.put(DataElement::new(
        tags::COMMAND_DATA_SET_TYPE,
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // affected SOP Instance UID
    obj.put(DataElement::new(
        tags::AFFECTED_SOP_INSTANCE_UID,
        VR::UI,
        dicom_value!(Str, storage_sop_instance_uid),
    ));

    obj
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

pub fn spawn(cmd: &str, updated_paths: Vec<PathBuf>) -> Process {
    self::imp::Process::new(cmd, updated_paths).expect("unable to spawn process")
}

pub use self::imp::Process;

#[cfg(target_family = "unix")]
mod imp {
    use libc::*;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;
    use std::sync::*;

    pub struct Process {
        pgid: pid_t,
        lock: Mutex<bool>,
        cvar: Condvar,
    }

    #[allow(unknown_lints)]
    #[allow(mutex_atomic)]
    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use nix::unistd::*;
            use std::fs::File;
            use std::io;
            use std::io::{Read, Write};
            use std::os::unix::io::FromRawFd;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            // command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
            // .spawn()
            // .and_then(|p| Ok(Process { pid: p.id() as i32 }))

            // Wait for child to call setpgid()
            // Else, we risk racing waitpid/killpg (mostly just in tests, but hey)
            let (r, w) = try!(pipe());

            match fork() {
                Ok(ForkResult::Parent { child, .. }) => {
                    {
                        let mut reader = unsafe { File::from_raw_fd(r) };
                        let mut buffer = vec![0];
                        let _ = reader.read_exact(&mut buffer);
                    }
                    let _ = close(w);

                    Ok(Process {
                        pgid: child,
                        lock: Mutex::new(false),
                        cvar: Condvar::new(),
                    })
                }
                Ok(ForkResult::Child) => {
                    let _ = setpgid(0, 0);

                    {
                        let mut writer = unsafe { File::from_raw_fd(w) };
                        let _ = writer.write_all(&[42]);
                    }
                    let _ = close(r);

                    let _ = command.exec();

                    // If we get here, there isn't much we can do
                    unsafe {
                        exit(1);
                    }
                }
                Err(e) => Err(io::Error::from(e)),
            }
        }

        pub fn kill(&self) {
            self.signal(SIGKILL);
        }

        pub fn pause(&self) {
            self.signal(SIGTSTP);
        }

        pub fn reap(&self) {
            use nix::sys::wait::*;

            let mut finished = true;
            loop {
                match waitpid(-self.pgid, Some(WNOHANG)) {
                    Ok(WaitStatus::Exited(_, _)) |
                    Ok(WaitStatus::Signaled(_, _, _)) => finished = finished && true,
                    Ok(_) => {
                        finished = false;
                        break;
                    }
                    Err(_) => break,
                }
            }

            if finished {
                let mut done = self.lock.lock().unwrap();
                *done = true;
                self.cvar.notify_one();
            }
        }

        pub fn resume(&self) {
            self.signal(SIGCONT);
        }

        fn signal(&self, sig: c_int) {
            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, sig);
            }

        }

        pub fn terminate(&self) {
            self.signal(SIGTERM);
        }

        pub fn wait(&self) {
            let mut done = self.lock.lock().unwrap();
            while !*done {
                done = self.cvar.wait(done).unwrap();
            }
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn()
                .and_then(|p| {
                    let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                    if r == 0 {
                        panic!("failed to add to job object: {}", last_err());
                    }

                    Ok(Process { job: job })
                })
        }

        pub fn kill(&self) {
            self.terminate();
        }

        pub fn pause(&self) {}

        pub fn reap(&self) {}

        pub fn resume(&self) {}

        pub fn terminate(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::PathBuf;

    use super::spawn;
    use super::get_longest_common_path;

    #[test]
    fn test_start() {
        let _ = spawn("echo hi", vec![]);
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<commit_msg>Use before_exec as process_exec landed in stable<commit_after>use std::path::PathBuf;

pub fn spawn(cmd: &str, updated_paths: Vec<PathBuf>) -> Process {
    self::imp::Process::new(cmd, updated_paths).expect("unable to spawn process")
}

pub use self::imp::Process;

#[cfg(target_family = "unix")]
mod imp {
    use libc::*;
    use std::io::Result;
    use std::path::PathBuf;
    use std::process::Command;
    use std::sync::*;

    pub struct Process {
        pgid: pid_t,
        lock: Mutex<bool>,
        cvar: Condvar,
    }

    #[allow(unknown_lints)]
    #[allow(mutex_atomic)]
    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use nix::unistd::*;
            use std::io;
            use std::os::unix::process::CommandExt;

            let mut command = Command::new("sh");
            command.arg("-c").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            // Until process_exec lands in stable, handle fork/exec ourselves
            command.before_exec(|| setpgid(0, 0).map_err(io::Error::from))
                .spawn()
                .and_then(|p| {
                    Ok(Process {
                           pgid: p.id() as i32,
                           lock: Mutex::new(false),
                           cvar: Condvar::new(),
                       })
                })
        }

        pub fn kill(&self) {
            self.signal(SIGKILL);
        }

        pub fn pause(&self) {
            self.signal(SIGTSTP);
        }

        pub fn reap(&self) {
            use nix::sys::wait::*;

            let mut finished = true;
            loop {
                match waitpid(-self.pgid, Some(WNOHANG)) {
                    Ok(WaitStatus::Exited(_, _)) |
                    Ok(WaitStatus::Signaled(_, _, _)) => finished = finished && true,
                    Ok(_) => {
                        finished = false;
                        break;
                    }
                    Err(_) => break,
                }
            }

            if finished {
                let mut done = self.lock.lock().unwrap();
                *done = true;
                self.cvar.notify_one();
            }
        }

        pub fn resume(&self) {
            self.signal(SIGCONT);
        }

        fn signal(&self, sig: c_int) {
            extern "C" {
                fn killpg(pgrp: pid_t, sig: c_int) -> c_int;
            }

            unsafe {
                killpg(self.pgid, sig);
            }

        }

        pub fn terminate(&self) {
            self.signal(SIGTERM);
        }

        pub fn wait(&self) {
            let mut done = self.lock.lock().unwrap();
            while !*done {
                done = self.cvar.wait(done).unwrap();
            }
        }
    }
}

#[cfg(target_family = "windows")]
mod imp {
    use std::io;
    use std::io::Result;
    use std::mem;
    use std::path::PathBuf;
    use std::process::Command;
    use kernel32::*;
    use winapi::*;

    pub struct Process {
        job: HANDLE,
    }

    impl Process {
        pub fn new(cmd: &str, updated_paths: Vec<PathBuf>) -> Result<Process> {
            use std::os::windows::io::IntoRawHandle;

            fn last_err() -> io::Error {
                io::Error::last_os_error()
            }

            let job = unsafe { CreateJobObjectW(0 as *mut _, 0 as *const _) };
            if job.is_null() {
                panic!("failed to create job object: {}", last_err());
            }

            let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = unsafe { mem::zeroed() };
            info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
            let r = unsafe {
                SetInformationJobObject(job,
                                        JobObjectExtendedLimitInformation,
                                        &mut info as *mut _ as LPVOID,
                                        mem::size_of_val(&info) as DWORD)
            };
            if r == 0 {
                panic!("failed to set job info: {}", last_err());
            }

            let mut command = Command::new("cmd.exe");
            command.arg("/C").arg(cmd);

            if let Some(single_path) = super::get_single_updated_path(&updated_paths) {
                command.env("WATCHEXEC_UPDATED_PATH", single_path);
            }

            if let Some(common_path) = super::get_longest_common_path(&updated_paths) {
                command.env("WATCHEXEC_COMMON_PATH", common_path);
            }

            command.spawn().and_then(|p| {
                let r = unsafe { AssignProcessToJobObject(job, p.into_raw_handle()) };
                if r == 0 {
                    panic!("failed to add to job object: {}", last_err());
                }

                Ok(Process { job: job })
            })
        }

        pub fn kill(&self) {
            self.terminate();
        }

        pub fn pause(&self) {}

        pub fn reap(&self) {}

        pub fn resume(&self) {}

        pub fn terminate(&self) {
            unsafe {
                let _ = TerminateJobObject(self.job, 1);
            }
        }

        pub fn wait(&self) {
            unsafe {
                let _ = WaitForSingleObject(self.job, INFINITE);
            }
        }
    }

    impl Drop for Process {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.job);
            }
        }
    }

    unsafe impl Send for Process {}
    unsafe impl Sync for Process {}
}

fn get_single_updated_path(paths: &[PathBuf]) -> Option<&str> {
    paths.get(0).and_then(|p| p.to_str())
}

fn get_longest_common_path(paths: &[PathBuf]) -> Option<String> {
    match paths.len() {
        0 => return None,
        1 => return paths[0].to_str().map(|ref_val| ref_val.to_string()),
        _ => {}
    };

    let mut longest_path: Vec<_> = paths[0].components().collect();

    for path in &paths[1..] {
        let mut greatest_distance = 0;
        for component_pair in path.components().zip(longest_path.iter()) {
            if component_pair.0 != *component_pair.1 {
                break;
            }

            greatest_distance += 1;
        }

        if greatest_distance != longest_path.len() {
            longest_path.truncate(greatest_distance);
        }
    }

    let mut result = PathBuf::new();
    for component in longest_path {
        result.push(component.as_os_str());
    }

    result.to_str().map(|ref_val| ref_val.to_string())
}

#[cfg(test)]
#[cfg(target_family = "unix")]
mod tests {
    use std::path::PathBuf;

    use super::spawn;
    use super::get_longest_common_path;

    #[test]
    fn test_start() {
        let _ = spawn("echo hi", vec![]);
    }

    #[test]
    fn longest_common_path_should_return_correct_value() {
        let single_path = vec![PathBuf::from("/tmp/random/")];
        let single_result = get_longest_common_path(&single_path).unwrap();
        assert_eq!(single_result, "/tmp/random/");

        let common_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/bye"),
                                PathBuf::from("/tmp/logs/fly")];

        let common_result = get_longest_common_path(&common_paths).unwrap();
        assert_eq!(common_result, "/tmp/logs");

        let diverging_paths = vec![PathBuf::from("/tmp/logs/hi"), PathBuf::from("/var/logs/hi")];

        let diverging_result = get_longest_common_path(&diverging_paths).unwrap();
        assert_eq!(diverging_result, "/");

        let uneven_paths = vec![PathBuf::from("/tmp/logs/hi"),
                                PathBuf::from("/tmp/logs/"),
                                PathBuf::from("/tmp/logs/bye")];

        let uneven_result = get_longest_common_path(&uneven_paths).unwrap();
        assert_eq!(uneven_result, "/tmp/logs");
    }
}
<|endoftext|>


<commit_before>use serde_json;

use std::cmp::{ Ord, Ordering };
use std::str::FromStr;
use git2::{ Time };
use super::{ Error, Result };

#[derive(Deserialize)]
pub struct Request {
  timestamp: Option<String>,
  #[serde(rename="reviewRef")]
  review_ref: Option<String>,
  #[serde(rename="targetRef")]
  target_ref: Option<String>,
  requester: Option<String>,
  reviewers: Option<Vec<String>>,
  description: Option<String>,
  #[serde(rename="baseCommit")]
  base_commit: Option<String>,
}

impl Request {
  pub fn from_str(s: &str) -> Result<Request> {
    serde_json::de::from_str(s).map_err(|err| From::from((err, s.to_string())))
  }

  pub fn timestamp(&self) -> Option<Time> {
    self.timestamp.as_ref()
      .and_then(|timestamp|
        FromStr::from_str(timestamp)
          .ok()
          .map(|time| Time::new(time, 0)))
  }

  pub fn review_ref(&self) -> Option<&String> {
    self.review_ref.as_ref()
  }

  pub fn target_ref(&self) -> Option<&String> {
    self.target_ref.as_ref()
  }

  pub fn requester(&self) -> Option<&String> {
    self.requester.as_ref()
  }

  pub fn reviewers(&self) -> Option<&Vec<String>> {
    self.reviewers.as_ref()
  }

  pub fn description(&self) -> Option<&String> {
    self.description.as_ref()
  }

  pub fn base_commit(&self) -> Option<&String> {
    self.base_commit.as_ref()
  }
}

pub struct ByTimestamp(pub Request);

impl Eq for ByTimestamp {
}

impl PartialEq for ByTimestamp {
  fn eq(&self, other: &Self) -> bool {
    self.0.timestamp().map(|t| t.seconds()).eq(&other.0.timestamp().map(|t| t.seconds()))
  }
}

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

impl Ord for ByTimestamp {
  fn cmp(&self, other: &Self) -> Ordering {
    self.0.timestamp().map(|t| t.seconds()).cmp(&other.0.timestamp().map(|t| t.seconds()))
  }
}
<commit_msg>&String -> &str<commit_after>use serde_json;

use std::cmp::{ Ord, Ordering };
use std::str::FromStr;
use git2::{ Time };
use super::{ Error, Result };

#[derive(Deserialize)]
pub struct Request {
  timestamp: Option<String>,
  #[serde(rename="reviewRef")]
  review_ref: Option<String>,
  #[serde(rename="targetRef")]
  target_ref: Option<String>,
  requester: Option<String>,
  reviewers: Option<Vec<String>>,
  description: Option<String>,
  #[serde(rename="baseCommit")]
  base_commit: Option<String>,
}

impl Request {
  pub fn from_str(s: &str) -> Result<Request> {
    serde_json::de::from_str(s).map_err(|err| From::from((err, s.to_string())))
  }

  pub fn timestamp(&self) -> Option<Time> {
    self.timestamp.as_ref()
      .and_then(|timestamp|
        FromStr::from_str(timestamp)
          .ok()
          .map(|time| Time::new(time, 0)))
  }

  pub fn review_ref(&self) -> Option<&str> {
    self.review_ref.as_ref().map(|s| &**s)
  }

  pub fn target_ref(&self) -> Option<&str> {
    self.target_ref.as_ref().map(|s| &**s)
  }

  pub fn requester(&self) -> Option<&str> {
    self.requester.as_ref().map(|s| &**s)
  }

  pub fn reviewers(&self) -> Option<Vec<&str>> {
    self.reviewers.as_ref().map(|v| v.iter().map(|s| &**s).collect())
  }

  pub fn description(&self) -> Option<&str> {
    self.description.as_ref().map(|s| &**s)
  }

  pub fn base_commit(&self) -> Option<&str> {
    self.base_commit.as_ref().map(|s| &**s)
  }
}

pub struct ByTimestamp(pub Request);

impl Eq for ByTimestamp {
}

impl PartialEq for ByTimestamp {
  fn eq(&self, other: &Self) -> bool {
    self.0.timestamp().map(|t| t.seconds()).eq(&other.0.timestamp().map(|t| t.seconds()))
  }
}

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

impl Ord for ByTimestamp {
  fn cmp(&self, other: &Self) -> Ordering {
    self.0.timestamp().map(|t| t.seconds()).cmp(&other.0.timestamp().map(|t| t.seconds()))
  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{Read, Cursor};

use bucket::Bucket;
use chrono::{DateTime, Utc};
use command::Command;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
use curl::easy::{Easy, List, ReadError};
use hex::ToHex;
use url::Url;
use serde_xml;

use serde_types::AwsError;
use signing;
use error::{S3Result, ErrorKind};

use EMPTY_PAYLOAD_SHA;
use LONG_DATE;

/// Collection of HTTP headers sent to S3 service, in key/value format.
pub type Headers = HashMap<String, String>;

/// Collection of HTTP query parameters sent to S3 service, in key/value
/// format.
pub type Query = HashMap<String, String>;

// Temporary structure for making a request
pub struct Request<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
}

impl<'a> Request<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> Request<'b> {
        Request {
            bucket,
            path,
            command,
            datetime: Utc::now(),
        }
    }

    fn url(&self) -> Url {
        let mut url_str = String::from("https://");
        url_str.push_str(self.bucket.host());
        url_str.push_str("/");
        url_str.push_str(self.bucket.name());
        if !self.path.starts_with('/') {
            url_str.push_str("/");
        }
        url_str.push_str(&signing::uri_encode(self.path, false));

        // Since every part of this URL is either pre-encoded or statically
        // generated, there's really no way this should fail.
        let mut url = Url::parse(&url_str).expect("static URL parsing");

        for (key, value) in &self.bucket.extra_query {
            url.query_pairs_mut().append_pair(key, value);
        }

        if let Command::List { prefix, delimiter, continuation_token } = self.command {
            let mut query_pairs = url.query_pairs_mut();
            delimiter.map(|d| query_pairs.append_pair("delimiter", d));
            query_pairs.append_pair("prefix", prefix);
            query_pairs.append_pair("list-type", "2");
            if let Some(token) = continuation_token {
                query_pairs.append_pair("continuation-token", token);
            }
        }

        url
    }

    fn content_length(&self) -> usize {
        match self.command {
            Command::Put { content, .. } => content.len(),
            _ => 0,
        }
    }

    fn content_type(&self) -> String {
        match self.command {
            Command::Put { content_type, .. } => content_type.into(),
            _ => "text/plain".into(),
        }
    }

    fn sha256(&self) -> String {
        match self.command {
            Command::Put { content, .. } => {
                let mut sha = Sha256::default();
                sha.input(content);
                sha.result().as_slice().to_hex()
            }
            _ => EMPTY_PAYLOAD_SHA.into(),
        }
    }

    fn long_date(&self) -> String {
        self.datetime.format(LONG_DATE).to_string()
    }

    fn canonical_request(&self, headers: &Headers) -> String {
        signing::canonical_request(self.command.http_verb(),
                                   &self.url(),
                                   headers,
                                   &self.sha256())
    }

    fn string_to_sign(&self, request: &str) -> String {
        signing::string_to_sign(&self.datetime, &self.bucket.region(), request)
    }

    fn signing_key(&self) -> Vec<u8> {
        signing::signing_key(&self.datetime,
                             self.bucket.secret_key(),
                             &self.bucket.region(),
                             "s3")
    }

    fn authorization(&self, headers: &Headers) -> String {
        let canonical_request = self.canonical_request(headers);
        let string_to_sign = self.string_to_sign(&canonical_request);
        let mut hmac = Hmac::<Sha256>::new(&self.signing_key());
        hmac.input(string_to_sign.as_bytes());
        let signature = hmac.result().code().to_hex();
        let signed_header = signing::signed_header_string(headers);
        signing::authorization_header(self.bucket.access_key(),
                                      &self.datetime,
                                      &self.bucket.region(),
                                      &signed_header,
                                      &signature)
    }

    fn headers(&self) -> S3Result<Headers> {
        // Generate this once, but it's used in more than one place.
        let sha256 = self.sha256();

        // Start with extra_headers, that way our headers replace anything with
        // the same name.
        let mut headers: Headers = self.bucket.extra_headers.clone();
        headers.insert("Host".into(), self.bucket.host().into());
        headers.insert("Content-Length".into(), self.content_length().to_string());
        headers.insert("Content-Type".into(), self.content_type());
        headers.insert("X-Amz-Content-Sha256".into(), sha256.clone());
        headers.insert("X-Amz-Date".into(), self.long_date());

        self.bucket.credentials().token.as_ref().map(|token| {
            headers.insert("X-Amz-Security-Token".into(), token.clone());
        });

        // This must be last, as it signs the other headers
        let authorization = self.authorization(&headers);
        headers.insert("Authorization".into(), authorization);

        // The format of RFC2822 is somewhat malleable, so including it in
        // signed headers can cause signature mismatches. We do include the
        // X-Amz-Date header, so requests are still properly limited to a date
        // range and can't be used again e.g. reply attacks. Adding this header
        // after the generation of the Authorization header leaves it out of
        // the signed headers.
        headers.insert("Date".into(), self.datetime.to_rfc2822());

        Ok(headers)
    }

    fn load_content(&self, handle: &mut Easy) -> S3Result<Cursor<&[u8]>> {
        if let Command::Put { content, .. } = self.command {
            try!(handle.put(true));
            try!(handle.post_field_size(content.len() as u64));
            Ok(Cursor::new(content))
        } else {
            Ok(Cursor::new(&[] as &[u8]))
        }
    }

    pub fn execute(&self) -> S3Result<(Vec<u8>, u32)> {
        let mut handle = Easy::new();
        handle.url(self.url().as_str())?;

        // Special handling to load PUT content
        let mut content_cursor = try!(self.load_content(&mut handle));

        // Set GET, PUT, etc
        handle.custom_request(self.command.http_verb())?;

        // Build and set a Curl List of headers
        let mut list = List::new();
        for (key, value) in &self.headers()? {
            let header = format!("{}: {}", key, value);
            list.append(&header)?;
        }
        handle.http_headers(list)?;

        if cfg!(feature = "no-verify-ssl") {
            handle.ssl_verify_peer(false)?;
        }

        // Run the transfer
        let mut dst = Vec::new();
        {
            let mut transfer = handle.transfer();

            transfer.read_function(|buf| content_cursor.read(buf).or(Err(ReadError::Abort)))?;

            transfer.write_function(|data| {
                dst.extend_from_slice(data);
                Ok(data.len())
            })?;

            transfer.perform()?;
        }
        let resp_code = handle.response_code()?;
        if resp_code < 300 {
            Ok((dst, resp_code))
        } else {
            let deserialized: AwsError = serde_xml::deserialize(dst.as_slice())?;
            let err = ErrorKind::AwsError {
                info: deserialized,
                status: resp_code,
                body: String::from_utf8_lossy(dst.as_slice()).into_owned(),
            };
            Err(err.into())
        }
    }
}
<commit_msg>Allowing custom region to optionally provide URL scheme<commit_after>use std::collections::HashMap;
use std::io::{Read, Cursor};

use bucket::Bucket;
use chrono::{DateTime, Utc};
use command::Command;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
use curl::easy::{Easy, List, ReadError};
use hex::ToHex;
use url::Url;
use serde_xml;

use serde_types::AwsError;
use signing;
use error::{S3Result, ErrorKind};

use EMPTY_PAYLOAD_SHA;
use LONG_DATE;

/// Collection of HTTP headers sent to S3 service, in key/value format.
pub type Headers = HashMap<String, String>;

/// Collection of HTTP query parameters sent to S3 service, in key/value
/// format.
pub type Query = HashMap<String, String>;

// Temporary structure for making a request
pub struct Request<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
}

impl<'a> Request<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> Request<'b> {
        Request {
            bucket,
            path,
            command,
            datetime: Utc::now(),
        }
    }

    fn url(&self) -> Url {
        let mut url_str = match self.bucket.host().find("://") {
            Some(_) => String::from(self.bucket.host()),
            None => format!("https://{}", self.bucket.host())
        };
        url_str.push_str("/");
        url_str.push_str(self.bucket.name());
        if !self.path.starts_with('/') {
            url_str.push_str("/");
        }
        url_str.push_str(&signing::uri_encode(self.path, false));

        // Since every part of this URL is either pre-encoded or statically
        // generated, there's really no way this should fail.
        let mut url = Url::parse(&url_str).expect("static URL parsing");

        for (key, value) in &self.bucket.extra_query {
            url.query_pairs_mut().append_pair(key, value);
        }

        if let Command::List { prefix, delimiter, continuation_token } = self.command {
            let mut query_pairs = url.query_pairs_mut();
            delimiter.map(|d| query_pairs.append_pair("delimiter", d));
            query_pairs.append_pair("prefix", prefix);
            query_pairs.append_pair("list-type", "2");
            if let Some(token) = continuation_token {
                query_pairs.append_pair("continuation-token", token);
            }
        }

        url
    }

    fn content_length(&self) -> usize {
        match self.command {
            Command::Put { content, .. } => content.len(),
            _ => 0,
        }
    }

    fn content_type(&self) -> String {
        match self.command {
            Command::Put { content_type, .. } => content_type.into(),
            _ => "text/plain".into(),
        }
    }

    fn sha256(&self) -> String {
        match self.command {
            Command::Put { content, .. } => {
                let mut sha = Sha256::default();
                sha.input(content);
                sha.result().as_slice().to_hex()
            }
            _ => EMPTY_PAYLOAD_SHA.into(),
        }
    }

    fn long_date(&self) -> String {
        self.datetime.format(LONG_DATE).to_string()
    }

    fn canonical_request(&self, headers: &Headers) -> String {
        signing::canonical_request(self.command.http_verb(),
                                   &self.url(),
                                   headers,
                                   &self.sha256())
    }

    fn string_to_sign(&self, request: &str) -> String {
        signing::string_to_sign(&self.datetime, &self.bucket.region(), request)
    }

    fn signing_key(&self) -> Vec<u8> {
        signing::signing_key(&self.datetime,
                             self.bucket.secret_key(),
                             &self.bucket.region(),
                             "s3")
    }

    fn authorization(&self, headers: &Headers) -> String {
        let canonical_request = self.canonical_request(headers);
        let string_to_sign = self.string_to_sign(&canonical_request);
        let mut hmac = Hmac::<Sha256>::new(&self.signing_key());
        hmac.input(string_to_sign.as_bytes());
        let signature = hmac.result().code().to_hex();
        let signed_header = signing::signed_header_string(headers);
        signing::authorization_header(self.bucket.access_key(),
                                      &self.datetime,
                                      &self.bucket.region(),
                                      &signed_header,
                                      &signature)
    }

    fn headers(&self) -> S3Result<Headers> {
        // Generate this once, but it's used in more than one place.
        let sha256 = self.sha256();

        // Start with extra_headers, that way our headers replace anything with
        // the same name.
        let mut headers: Headers = self.bucket.extra_headers.clone();
        headers.insert("Host".into(), self.bucket.host().into());
        headers.insert("Content-Length".into(), self.content_length().to_string());
        headers.insert("Content-Type".into(), self.content_type());
        headers.insert("X-Amz-Content-Sha256".into(), sha256.clone());
        headers.insert("X-Amz-Date".into(), self.long_date());

        self.bucket.credentials().token.as_ref().map(|token| {
            headers.insert("X-Amz-Security-Token".into(), token.clone());
        });

        // This must be last, as it signs the other headers
        let authorization = self.authorization(&headers);
        headers.insert("Authorization".into(), authorization);

        // The format of RFC2822 is somewhat malleable, so including it in
        // signed headers can cause signature mismatches. We do include the
        // X-Amz-Date header, so requests are still properly limited to a date
        // range and can't be used again e.g. reply attacks. Adding this header
        // after the generation of the Authorization header leaves it out of
        // the signed headers.
        headers.insert("Date".into(), self.datetime.to_rfc2822());

        Ok(headers)
    }

    fn load_content(&self, handle: &mut Easy) -> S3Result<Cursor<&[u8]>> {
        if let Command::Put { content, .. } = self.command {
            try!(handle.put(true));
            try!(handle.post_field_size(content.len() as u64));
            Ok(Cursor::new(content))
        } else {
            Ok(Cursor::new(&[] as &[u8]))
        }
    }

    pub fn execute(&self) -> S3Result<(Vec<u8>, u32)> {
        let mut handle = Easy::new();
        handle.url(self.url().as_str())?;

        // Special handling to load PUT content
        let mut content_cursor = try!(self.load_content(&mut handle));

        // Set GET, PUT, etc
        handle.custom_request(self.command.http_verb())?;

        // Build and set a Curl List of headers
        let mut list = List::new();
        for (key, value) in &self.headers()? {
            let header = format!("{}: {}", key, value);
            list.append(&header)?;
        }
        handle.http_headers(list)?;

        if cfg!(feature = "no-verify-ssl") {
            handle.ssl_verify_peer(false)?;
        }

        // Run the transfer
        let mut dst = Vec::new();
        {
            let mut transfer = handle.transfer();

            transfer.read_function(|buf| content_cursor.read(buf).or(Err(ReadError::Abort)))?;

            transfer.write_function(|data| {
                dst.extend_from_slice(data);
                Ok(data.len())
            })?;

            transfer.perform()?;
        }
        let resp_code = handle.response_code()?;
        if resp_code < 300 {
            Ok((dst, resp_code))
        } else {
            let deserialized: AwsError = serde_xml::deserialize(dst.as_slice())?;
            let err = ErrorKind::AwsError {
                info: deserialized,
                status: resp_code,
                body: String::from_utf8_lossy(dst.as_slice()).into_owned(),
            };
            Err(err.into())
        }
    }
}

#[cfg(test)]
mod tests {
    use bucket::Bucket;
    use command::Command;
    use credentials::Credentials;
    use request::Request;

    #[test]
    fn url_uses_https_by_default() {
        let region = "custom-region".parse().unwrap();
        let bucket = Bucket::new("my-first-bucket", region, Credentials::default());
        let path = "/my-first/path";
        let request = Request::new(&bucket, path, Command::Get);

        assert_eq!(request.url().scheme(), "https");
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined() {
        let region = "http://custom-region".parse().unwrap();
        let bucket = Bucket::new("my-second-bucket", region, Credentials::default());
        let path = "/my-second/path";
        let request = Request::new(&bucket, path, Command::Get);

        assert_eq!(request.url().scheme(), "http");
    }
}
<|endoftext|>


<commit_before>#![crate_name = "rho"]
extern crate ncurses;

mod host;
mod event;
mod client;
mod buffer;

use std::sync::Arc;
use std::sync::mpsc;
use std::sync::RwLock;
use std::sync::mpsc::{Receiver, Sender};

use host::Host;
use client::Client;
use buffer::Buffer;
use event::InputEvent;

use host::CursesHost;
pub use client::GenericClient;

pub struct Editor {
    host: Host,
    client: Client,
    buffers: Arc<RwLock<Vec<Buffer>>>,
}

pub impl Editor {
    pub fn new() {
        let buffers = RwLock::new(vec![Buffer::new()]);
        let (sender, recvr): (Sender<InputEvent>, Receiver<InputEvent>) = mpsc::channel();
        let (host, client) = (CursesHost::new(buffers, sender), GenericClient::new(buffers,recvr));
    }

    pub fn run(&self) {
        self.client.listen();
        self.host.run();
    }
}
<commit_msg>Proper use of generics<commit_after>#![crate_name = "rho"]
extern crate ncurses;

mod host;
mod event;
mod client;
mod buffer;

use std::sync::Arc;
use std::sync::mpsc;
use std::sync::RwLock;
use std::sync::mpsc::{Receiver, Sender};

use host::Host;
use client::Client;
use buffer::Buffer;
use event::InputEvent;

use host::CursesHost;
pub use client::GenericClient;

pub struct Editor<'a, H: 'a + Host, C: 'a + Client> {
    host: &'a H,
    client: &'a C,
    buffers: Arc<RwLock<Vec<Buffer>>>,
}

pub impl<'a> Editor<'a, CursesHost, GenericClient> {
    pub fn new() -> Editor<'a, CursesHost, GenericClient> {
        let buffers = Arc::new(RwLock::new(vec![Buffer::new()]));
        let (sender, recvr): (Sender<InputEvent>, Receiver<InputEvent>) = mpsc::channel();
        let (host, client) = (CursesHost::new(buffers.clone(), sender), GenericClient::new(buffers.clone(), recvr));
        Editor{host: &host, client: &client, buffers: buffers}
    }

    pub fn run(&self) {
        self.client.listen();
        self.host.run();
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate valico;
extern crate "rustc-serialize" as serialize;

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

mod builder;
mod helpers;<commit_msg>refactor: rustup<commit_after>#![feature(plugin)]

extern crate valico;
extern crate "rustc-serialize" as serialize;

#[plugin]
extern crate regex_macros;
extern crate regex;

mod builder;
mod helpers;<|endoftext|>


<commit_before>extern crate lisp_rs;

#[cfg(test)]
mod tests {
    use lisp_rs::atom::*;
    use lisp_rs::token::*;
    use lisp_rs::token::Operator::*;

    // #[test]
    fn test_operator() {
        let result = parse_Op("+");
        assert_eq!(result, Ok(Atom::from(Add)));

        let result = parse_Op("-");
        assert_eq!(result, Ok(Atom::from(Sub)));

        let result = parse_Op("*");
        assert_eq!(result, Ok(Atom::from(Mul)));

        let result = parse_Op("/");
        assert_eq!(result, Ok(Atom::from(Div)));
    }

    // #[test]
    // fn test_numeric() {
    //     let result = parser(numeric).parse("1000");
    //     assert_eq!(result, Ok((Expr::from(1000), "")));
    // }
    //
    // #[test]
    // fn test_symbol() {
    //     let result = parser(symbol).parse("+1");
    //     assert_eq!(result, Ok((Expr::Atom(Atom::Sym(Add)), "1")));
    // }
    //
    // #[test]
    // fn test_expr() {
    //     let result = parser(expr).parse("( 1 2 3 )");
    //     let expr = Expr::from(vec![1, 2, 3]);
    //     assert_eq!(result, Ok((expr, "")));
    // }
}
<commit_msg>Change lisp_rs to lrs in tests folder<commit_after>extern crate lrs;

#[cfg(test)]
mod tests {
    use lrs::atom::*;
    use lrs::token::*;
    use lrs::token::Operator::*;

    // #[test]
    fn test_operator() {
        let result = parse_Op("+");
        assert_eq!(result, Ok(Atom::from(Add)));

        let result = parse_Op("-");
        assert_eq!(result, Ok(Atom::from(Sub)));

        let result = parse_Op("*");
        assert_eq!(result, Ok(Atom::from(Mul)));

        let result = parse_Op("/");
        assert_eq!(result, Ok(Atom::from(Div)));
    }

    // #[test]
    // fn test_numeric() {
    //     let result = parser(numeric).parse("1000");
    //     assert_eq!(result, Ok((Expr::from(1000), "")));
    // }
    //
    // #[test]
    // fn test_symbol() {
    //     let result = parser(symbol).parse("+1");
    //     assert_eq!(result, Ok((Expr::Atom(Atom::Sym(Add)), "1")));
    // }
    //
    // #[test]
    // fn test_expr() {
    //     let result = parser(expr).parse("( 1 2 3 )");
    //     let expr = Expr::from(vec![1, 2, 3]);
    //     assert_eq!(result, Ok((expr, "")));
    // }
}
<|endoftext|>


<commit_before>use vm::VmResult;
use internal::js::{JsObject, Value, ValueInternal, Object, build};
use internal::mem::Handle;
use internal::vm::{Lock, LockState};
use scope::Scope;
use neon_sys;
use neon_sys::raw;
use neon_sys::buf::Buf;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct JsBuffer(raw::Local);

impl JsBuffer {
    pub fn new<'a, T: Scope<'a>>(_: &mut T, size: u32) -> VmResult<Handle<'a, JsBuffer>> {
        build(|out| { unsafe { neon_sys::buffer::new(out, size) } })
    }
}

impl ValueInternal for JsBuffer {
    fn to_raw(self) -> raw::Local { self.0 }

    fn from_raw(h: raw::Local) -> Self { JsBuffer(h) }

    fn is_typeof<Other: Value>(other: Other) -> bool {
        unsafe { neon_sys::tag::is_buffer(other.to_raw()) }
    }
}

impl Value for JsBuffer { }

impl Object for JsBuffer { }

impl<'a> Lock for Handle<'a, JsBuffer> {
    type Internals = Buf<'a>;

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        let mut result = Buf::uninitialized();
        neon_sys::buffer::data(&mut result, self.to_raw());
        state.use_buffer(&result);
        result
    }
}
<commit_msg>unused import<commit_after>use vm::VmResult;
use internal::js::{Value, ValueInternal, Object, build};
use internal::mem::Handle;
use internal::vm::{Lock, LockState};
use scope::Scope;
use neon_sys;
use neon_sys::raw;
use neon_sys::buf::Buf;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct JsBuffer(raw::Local);

impl JsBuffer {
    pub fn new<'a, T: Scope<'a>>(_: &mut T, size: u32) -> VmResult<Handle<'a, JsBuffer>> {
        build(|out| { unsafe { neon_sys::buffer::new(out, size) } })
    }
}

impl ValueInternal for JsBuffer {
    fn to_raw(self) -> raw::Local { self.0 }

    fn from_raw(h: raw::Local) -> Self { JsBuffer(h) }

    fn is_typeof<Other: Value>(other: Other) -> bool {
        unsafe { neon_sys::tag::is_buffer(other.to_raw()) }
    }
}

impl Value for JsBuffer { }

impl Object for JsBuffer { }

impl<'a> Lock for Handle<'a, JsBuffer> {
    type Internals = Buf<'a>;

    unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
        let mut result = Buf::uninitialized();
        neon_sys::buffer::data(&mut result, self.to_raw());
        state.use_buffer(&result);
        result
    }
}
<|endoftext|>


<commit_before>//! This module provides a way to create wasm modules that is backed in
//! a native Rust code.

use std::sync::Arc;
use std::collections::HashMap;
use std::borrow::Cow;
use parking_lot::RwLock;
use elements::{Internal, ValueType};
use interpreter::Error;
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
	CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableInstance, VariableType};

/// Min index of native function.
pub const NATIVE_INDEX_FUNC_MIN: u32 = 10001;
/// Min index of native global.
pub const NATIVE_INDEX_GLOBAL_MIN: u32 = 20001;

/// User functions executor.
pub trait UserFunctionExecutor {
	/// Execute function with given name.
	fn execute(&mut self, name: &str, context: CallerContext) -> Result<Option<RuntimeValue>, Error>;
}

/// User function descriptor
#[derive(Debug, Clone)]
pub enum UserFunctionDescriptor {
	/// Static function definition
	Static(&'static str, &'static [ValueType], Option<ValueType>),
	/// Dynamic heap function definition
	Heap(String, Vec<ValueType>, Option<ValueType>),
}

impl UserFunctionDescriptor {
	/// New function with statically known params
	pub fn statik(name: &'static str, params: &'static [ValueType], result: Option<ValueType>) -> Self {
		UserFunctionDescriptor::Static(name, params, result)
	}

	/// New function with statically unknown params
	pub fn heap(name: String, params: Vec<ValueType>, result: Option<ValueType>) -> Self {
		UserFunctionDescriptor::Heap(name, params, result)
	}

	/// Name of the function
	pub fn name(&self) -> &str {
		match self {
			&UserFunctionDescriptor::Static(name, _, _) => name,
			&UserFunctionDescriptor::Heap(ref name, _, _) => name,
		}
	}

	/// Arguments of the function
	pub fn params(&self) -> &[ValueType] {
		match self {
			&UserFunctionDescriptor::Static(_, params, _) => params,
			&UserFunctionDescriptor::Heap(_, ref params, _) => params,
		}
	}

	/// Return type of the function
	pub fn return_type(&self) -> Option<ValueType> {
		match self {
			&UserFunctionDescriptor::Static(_, _, result) => result,
			&UserFunctionDescriptor::Heap(_, _, result) => result,
		}
	}
}

/// Set of user-defined module elements.
pub struct UserDefinedElements<'a> {
	/// User globals list.
	pub globals: HashMap<String, Arc<VariableInstance>>,
	/// User functions list.
	pub functions: Cow<'static, [UserFunctionDescriptor]>,
	/// Functions executor.
	pub executor: Option<&'a mut UserFunctionExecutor>,
}

/// Native module instance.
pub struct NativeModuleInstance<'a> {
	/// Underlying module reference.
	base: Arc<ModuleInstanceInterface>,
	/// User function executor.
	executor: RwLock<Option<&'a mut UserFunctionExecutor>>,
	/// By-name functions index.
	functions_by_name: HashMap<String, u32>,
	/// User functions list.
	functions: Cow<'static, [UserFunctionDescriptor]>,
	/// By-name functions index.
	globals_by_name: HashMap<String, u32>,
	/// User globals list.
	globals: Vec<Arc<VariableInstance>>,
}

impl<'a> NativeModuleInstance<'a> {
	/// Create new native module
	pub fn new(base: Arc<ModuleInstanceInterface>, elements: UserDefinedElements<'a>) -> Result<Self, Error> {
		if !elements.functions.is_empty() && elements.executor.is_none() {
			return Err(Error::Function("trying to construct native env module with functions, but without executor".into()));
		}

		Ok(NativeModuleInstance {
			base: base,
			executor: RwLock::new(elements.executor),
			functions_by_name: elements.functions.iter().enumerate().map(|(i, f)| (f.name().to_owned(), i as u32)).collect(),
			functions: elements.functions,
			globals_by_name: elements.globals.iter().enumerate().map(|(i, (g_name, _))| (g_name.to_owned(), i as u32)).collect(),
			globals: elements.globals.into_iter().map(|(_, g)| g).collect(),
		})
	}
}

impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
	fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.base.execute_index(index, params)
	}

	fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.base.execute_export(name, params)
	}

	fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
		if let Some(index) = self.functions_by_name.get(name) {
			let composite_index = NATIVE_INDEX_FUNC_MIN + *index;
			match required_type {
				&ExportEntryType::Any => return Ok(Internal::Function(composite_index)),
				&ExportEntryType::Function(ref required_type) => {
					let actual_type = self.function_type(ItemIndex::Internal(composite_index))
						.expect(
							"by_name contains index; function_type succeeds for all functions from by_name; qed",
						);
					return if actual_type == *required_type {
						Ok(Internal::Function(composite_index))
					} else {
						Err(Error::Validation(format!(
							"Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
							index,
							required_type.params(),
							required_type.return_type(),
							actual_type.params(),
							actual_type.return_type()
						)))
					};
				}
				_ => (),
			}
		}
		if let Some(index) = self.globals_by_name.get(name) {
			let composite_index = NATIVE_INDEX_GLOBAL_MIN + *index;
			match required_type {
				&ExportEntryType::Any => {
					return Ok(Internal::Global(composite_index))
				}
				&ExportEntryType::Global(ref required_type) => {
					let actual_type = self.globals
						.get(*index as usize)
						.expect(
							"globals_by_name maps to indexes of globals; index read from globals_by_name; qed",
						)
						.variable_type();
					return if actual_type == *required_type {
						Ok(Internal::Global(composite_index))
					} else {
						Err(Error::Validation(format!(
							"Export global type {} mismatch. Expected type {:?} when got {:?}",
							index,
							required_type,
							actual_type
						)))
					};
				}
				_ => (),
			}
		}

		self.base.export_entry(name, required_type)
	}

	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
		self.base.table(index)
	}

	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
		self.base.memory(index)
	}

	fn global<'b>(&self, global_index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<Arc<VariableInstance>, Error> {
		let index = match global_index {
			ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
			ItemIndex::External(_) => unreachable!("trying to get global, exported by native env module"),
		};

		if index < NATIVE_INDEX_GLOBAL_MIN {
			return self.base.global(global_index, variable_type, externals);
		}

		self.globals
			.get((index - NATIVE_INDEX_GLOBAL_MIN) as usize)
			.cloned()
			.ok_or(Error::Native(format!("trying to get native global with index {}", index)))
	}

	fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
		let index = match function_index {
			ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
			ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"),
		};

		if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN {
			return self.base.function_type(function_index);
		}

		Ok(FunctionSignature::User(self.functions
			.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
			.ok_or(Error::Native(format!("missing native env function with index {}", index)))?))
	}

	fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
		self.function_type(ItemIndex::Internal(type_index))
	}

	fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
		self.base.function_reference(index, externals)
	}

	fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
		self.base.function_reference_indirect(table_idx, type_idx, func_idx, externals)
	}

	fn function_body<'b>(&'b self, _internal_index: u32) -> Result<Option<InternalFunction<'b>>, Error> {
		Ok(None)
	}

	fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> {
		if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN {
			return self.base.call_internal_function(outer, index);
		}

		self.functions
			.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
			.ok_or(Error::Native(format!("trying to call native function with index {}", index)).into())
			.and_then(|f| self.executor.write()
				.as_mut()
				.expect("function existss; if function exists, executor must also exists [checked in constructor]; qed")
				.execute(&f.name(), outer))
	}
}

/// Create wrapper for a module with given native user functions.
pub fn native_module<'a>(base: Arc<ModuleInstanceInterface>, user_elements: UserDefinedElements<'a>) -> Result<NativeModuleInstance, Error> {
	NativeModuleInstance::new(base, user_elements)
}

impl<'a> PartialEq for UserFunctionDescriptor {
	fn eq(&self, other: &Self) -> bool {
		self.params() == other.params()
			&& self.return_type() == other.return_type()
	}
}
<commit_msg>Update doc<commit_after>
use std::sync::Arc;
use std::collections::HashMap;
use std::borrow::Cow;
use parking_lot::RwLock;
use elements::{Internal, ValueType};
use interpreter::Error;
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
	CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableInstance, VariableType};

/// Min index of native function.
pub const NATIVE_INDEX_FUNC_MIN: u32 = 10001;
/// Min index of native global.
pub const NATIVE_INDEX_GLOBAL_MIN: u32 = 20001;

/// User functions executor.
pub trait UserFunctionExecutor {
	/// Execute function with given name.
	fn execute(&mut self, name: &str, context: CallerContext) -> Result<Option<RuntimeValue>, Error>;
}

/// User function descriptor
#[derive(Debug, Clone)]
pub enum UserFunctionDescriptor {
	/// Static function definition
	Static(&'static str, &'static [ValueType], Option<ValueType>),
	/// Dynamic heap function definition
	Heap(String, Vec<ValueType>, Option<ValueType>),
}

impl UserFunctionDescriptor {
	/// New function with statically known params
	pub fn statik(name: &'static str, params: &'static [ValueType], result: Option<ValueType>) -> Self {
		UserFunctionDescriptor::Static(name, params, result)
	}

	/// New function with statically unknown params
	pub fn heap(name: String, params: Vec<ValueType>, result: Option<ValueType>) -> Self {
		UserFunctionDescriptor::Heap(name, params, result)
	}

	/// Name of the function
	pub fn name(&self) -> &str {
		match self {
			&UserFunctionDescriptor::Static(name, _, _) => name,
			&UserFunctionDescriptor::Heap(ref name, _, _) => name,
		}
	}

	/// Arguments of the function
	pub fn params(&self) -> &[ValueType] {
		match self {
			&UserFunctionDescriptor::Static(_, params, _) => params,
			&UserFunctionDescriptor::Heap(_, ref params, _) => params,
		}
	}

	/// Return type of the function
	pub fn return_type(&self) -> Option<ValueType> {
		match self {
			&UserFunctionDescriptor::Static(_, _, result) => result,
			&UserFunctionDescriptor::Heap(_, _, result) => result,
		}
	}
}

/// Set of user-defined module elements.
pub struct UserDefinedElements<'a> {
	/// User globals list.
	pub globals: HashMap<String, Arc<VariableInstance>>,
	/// User functions list.
	pub functions: Cow<'static, [UserFunctionDescriptor]>,
	/// Functions executor.
	pub executor: Option<&'a mut UserFunctionExecutor>,
}

/// Native module instance.
pub struct NativeModuleInstance<'a> {
	/// Underlying module reference.
	base: Arc<ModuleInstanceInterface>,
	/// User function executor.
	executor: RwLock<Option<&'a mut UserFunctionExecutor>>,
	/// By-name functions index.
	functions_by_name: HashMap<String, u32>,
	/// User functions list.
	functions: Cow<'static, [UserFunctionDescriptor]>,
	/// By-name functions index.
	globals_by_name: HashMap<String, u32>,
	/// User globals list.
	globals: Vec<Arc<VariableInstance>>,
}

impl<'a> NativeModuleInstance<'a> {
	/// Create new native module
	pub fn new(base: Arc<ModuleInstanceInterface>, elements: UserDefinedElements<'a>) -> Result<Self, Error> {
		if !elements.functions.is_empty() && elements.executor.is_none() {
			return Err(Error::Function("trying to construct native env module with functions, but without executor".into()));
		}

		Ok(NativeModuleInstance {
			base: base,
			executor: RwLock::new(elements.executor),
			functions_by_name: elements.functions.iter().enumerate().map(|(i, f)| (f.name().to_owned(), i as u32)).collect(),
			functions: elements.functions,
			globals_by_name: elements.globals.iter().enumerate().map(|(i, (g_name, _))| (g_name.to_owned(), i as u32)).collect(),
			globals: elements.globals.into_iter().map(|(_, g)| g).collect(),
		})
	}
}

impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
	fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.base.execute_index(index, params)
	}

	fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.base.execute_export(name, params)
	}

	fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
		if let Some(index) = self.functions_by_name.get(name) {
			let composite_index = NATIVE_INDEX_FUNC_MIN + *index;
			match required_type {
				&ExportEntryType::Any => return Ok(Internal::Function(composite_index)),
				&ExportEntryType::Function(ref required_type) => {
					let actual_type = self.function_type(ItemIndex::Internal(composite_index))
						.expect(
							"by_name contains index; function_type succeeds for all functions from by_name; qed",
						);
					return if actual_type == *required_type {
						Ok(Internal::Function(composite_index))
					} else {
						Err(Error::Validation(format!(
							"Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
							index,
							required_type.params(),
							required_type.return_type(),
							actual_type.params(),
							actual_type.return_type()
						)))
					};
				}
				_ => (),
			}
		}
		if let Some(index) = self.globals_by_name.get(name) {
			let composite_index = NATIVE_INDEX_GLOBAL_MIN + *index;
			match required_type {
				&ExportEntryType::Any => {
					return Ok(Internal::Global(composite_index))
				}
				&ExportEntryType::Global(ref required_type) => {
					let actual_type = self.globals
						.get(*index as usize)
						.expect(
							"globals_by_name maps to indexes of globals; index read from globals_by_name; qed",
						)
						.variable_type();
					return if actual_type == *required_type {
						Ok(Internal::Global(composite_index))
					} else {
						Err(Error::Validation(format!(
							"Export global type {} mismatch. Expected type {:?} when got {:?}",
							index,
							required_type,
							actual_type
						)))
					};
				}
				_ => (),
			}
		}

		self.base.export_entry(name, required_type)
	}

	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
		self.base.table(index)
	}

	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
		self.base.memory(index)
	}

	fn global<'b>(&self, global_index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<Arc<VariableInstance>, Error> {
		let index = match global_index {
			ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
			ItemIndex::External(_) => unreachable!("trying to get global, exported by native env module"),
		};

		if index < NATIVE_INDEX_GLOBAL_MIN {
			return self.base.global(global_index, variable_type, externals);
		}

		self.globals
			.get((index - NATIVE_INDEX_GLOBAL_MIN) as usize)
			.cloned()
			.ok_or(Error::Native(format!("trying to get native global with index {}", index)))
	}

	fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
		let index = match function_index {
			ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
			ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"),
		};

		if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN {
			return self.base.function_type(function_index);
		}

		Ok(FunctionSignature::User(self.functions
			.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
			.ok_or(Error::Native(format!("missing native env function with index {}", index)))?))
	}

	fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
		self.function_type(ItemIndex::Internal(type_index))
	}

	fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
		self.base.function_reference(index, externals)
	}

	fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
		self.base.function_reference_indirect(table_idx, type_idx, func_idx, externals)
	}

	fn function_body<'b>(&'b self, _internal_index: u32) -> Result<Option<InternalFunction<'b>>, Error> {
		Ok(None)
	}

	fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> {
		if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN {
			return self.base.call_internal_function(outer, index);
		}

		self.functions
			.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
			.ok_or(Error::Native(format!("trying to call native function with index {}", index)).into())
			.and_then(|f| self.executor.write()
				.as_mut()
				.expect("function existss; if function exists, executor must also exists [checked in constructor]; qed")
				.execute(&f.name(), outer))
	}
}

/// Create wrapper for a module with given native user functions .
///
/// # Examples
///
/// ```rust
/// use parity_wasm::interpreter::{CallerContext, Error, ExecutionParams, ExportEntryType,
///                                FunctionSignature, ItemIndex, ModuleInstance,
///                                ModuleInstanceInterface, ProgramInstance, RuntimeValue,
///                                UserDefinedElements, UserError, UserFunctionDescriptor,
///                                UserFunctionExecutor};
///
/// struct MyExecutor;
///
/// impl UserFunctionExecutor for MyExecutor {
///     fn execute(
///         &mut self,
///         name: &str,
///         context: CallerContext,
///     ) -> Result<Option<RuntimeValue>, Error> {
///         match name {
///             "add" => {
///                 // fn add(a: u32, b: u32) -> u32
///                 let b = context.value_stack.pop_as::<u32>()? as u32;
///                 let a = context.value_stack.pop_as::<u32>()? as u32;
///                 let sum = a + b;
///                 Ok(Some(RuntimeValue::I32(sum as i32)))
///             }
///             _ => Err(Error::Trap("not implemented".into()).into()),
///         }
///     }
/// }
/// ```
pub fn native_module<'a>(base: Arc<ModuleInstanceInterface>, user_elements: UserDefinedElements<'a>) -> Result<NativeModuleInstance, Error> {
	NativeModuleInstance::new(base, user_elements)
}

impl<'a> PartialEq for UserFunctionDescriptor {
	fn eq(&self, other: &Self) -> bool {
		self.params() == other.params()
			&& self.return_type() == other.return_type()
	}
}
<|endoftext|>