<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::ffi::CStr;
use std::fmt::{self, Display};
use std::io::{Read, Seek, SeekFrom};
use std::mem;
use std::os::unix::io::AsRawFd;

use sys_util::{GuestAddress, GuestMemory};

#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
#[allow(clippy::all)]
mod elf;

#[derive(Debug, PartialEq)]
pub enum Error {
    BigEndianElfOnLittle,
    CommandLineCopy,
    CommandLineOverflow,
    InvalidElfMagicNumber,
    InvalidProgramHeaderSize,
    InvalidProgramHeaderOffset,
    InvalidProgramHeaderAddress,
    ReadElfHeader,
    ReadKernelImage,
    ReadProgramHeader,
    SeekKernelStart,
    SeekElfStart,
    SeekProgramHeader,
}
pub type Result<T> = std::result::Result<T, Error>;

impl std::error::Error for Error {}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        let description = match self {
            BigEndianElfOnLittle => "trying to load big-endian binary on little-endian machine",
            CommandLineCopy => "failed writing command line to guest memory",
            CommandLineOverflow => "command line overflowed guest memory",
            InvalidElfMagicNumber => "invalid Elf magic number",
            InvalidProgramHeaderSize => "invalid program header size",
            InvalidProgramHeaderOffset => "invalid program header offset",
            InvalidProgramHeaderAddress => "invalid Program Header Address",
            ReadElfHeader => "unable to read elf header",
            ReadKernelImage => "unable to read kernel image",
            ReadProgramHeader => "unable to read program header",
            SeekKernelStart => "unable to seek to kernel start",
            SeekElfStart => "unable to seek to elf start",
            SeekProgramHeader => "unable to seek to program header",
        };

        write!(f, "kernel loader: {}", description)
    }
}

/// Loads a kernel from a vmlinux elf image to a slice
///
/// # Arguments
///
/// * `guest_mem` - The guest memory region the kernel is written to.
/// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
/// * `kernel_image` - Input vmlinux image.
pub fn load_kernel<F>(
    guest_mem: &GuestMemory,
    kernel_start: GuestAddress,
    kernel_image: &mut F,
) -> Result<u64>
where
    F: Read + Seek + AsRawFd,
{
    let mut ehdr: elf::Elf64_Ehdr = Default::default();
    kernel_image
        .seek(SeekFrom::Start(0))
        .map_err(|_| Error::SeekElfStart)?;
    unsafe {
        // read_struct is safe when reading a POD struct.  It can be used and dropped without issue.
        sys_util::read_struct(kernel_image, &mut ehdr).map_err(|_| Error::ReadElfHeader)?;
    }

    // Sanity checks
    if ehdr.e_ident[elf::EI_MAG0 as usize] != elf::ELFMAG0 as u8
        || ehdr.e_ident[elf::EI_MAG1 as usize] != elf::ELFMAG1
        || ehdr.e_ident[elf::EI_MAG2 as usize] != elf::ELFMAG2
        || ehdr.e_ident[elf::EI_MAG3 as usize] != elf::ELFMAG3
    {
        return Err(Error::InvalidElfMagicNumber);
    }
    if ehdr.e_ident[elf::EI_DATA as usize] != elf::ELFDATA2LSB as u8 {
        return Err(Error::BigEndianElfOnLittle);
    }
    if ehdr.e_phentsize as usize != mem::size_of::<elf::Elf64_Phdr>() {
        return Err(Error::InvalidProgramHeaderSize);
    }
    if (ehdr.e_phoff as usize) < mem::size_of::<elf::Elf64_Ehdr>() {
        // If the program header is backwards, bail.
        return Err(Error::InvalidProgramHeaderOffset);
    }

    kernel_image
        .seek(SeekFrom::Start(ehdr.e_phoff))
        .map_err(|_| Error::SeekProgramHeader)?;
    let phdrs: Vec<elf::Elf64_Phdr> = unsafe {
        // Reading the structs is safe for a slice of POD structs.
        sys_util::read_struct_slice(kernel_image, ehdr.e_phnum as usize)
            .map_err(|_| Error::ReadProgramHeader)?
    };

    let mut kernel_end = 0;

    // Read in each section pointed to by the program headers.
    for phdr in &phdrs {
        if phdr.p_type != elf::PT_LOAD || phdr.p_filesz == 0 {
            continue;
        }

        kernel_image
            .seek(SeekFrom::Start(phdr.p_offset))
            .map_err(|_| Error::SeekKernelStart)?;

        let mem_offset = kernel_start
            .checked_add(phdr.p_paddr)
            .ok_or(Error::InvalidProgramHeaderAddress)?;
        guest_mem
            .read_to_memory(mem_offset, kernel_image, phdr.p_filesz as usize)
            .map_err(|_| Error::ReadKernelImage)?;

        kernel_end = mem_offset.offset() + phdr.p_memsz;
    }

    Ok(kernel_end)
}

/// Writes the command line string to the given memory slice.
///
/// # Arguments
///
/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
/// * `guest_addr` - The address in `guest_mem` at which to load the command line.
/// * `cmdline` - The kernel command line.
pub fn load_cmdline(
    guest_mem: &GuestMemory,
    guest_addr: GuestAddress,
    cmdline: &CStr,
) -> Result<()> {
    let len = cmdline.to_bytes().len();
    if len == 0 {
        return Ok(());
    }

    let end = guest_addr
        .checked_add(len as u64 + 1)
        .ok_or(Error::CommandLineOverflow)?; // Extra for null termination.
    if end > guest_mem.end_addr() {
        return Err(Error::CommandLineOverflow)?;
    }

    guest_mem
        .write_at_addr(cmdline.to_bytes_with_nul(), guest_addr)
        .map_err(|_| Error::CommandLineCopy)?;

    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::File;
    use std::io::Write;
    use sys_util::{GuestAddress, GuestMemory, SharedMemory};

    const MEM_SIZE: u64 = 0x8000;

    fn create_guest_mem() -> GuestMemory {
        GuestMemory::new(&vec![(GuestAddress(0x0), MEM_SIZE)]).unwrap()
    }

    #[test]
    fn cmdline_overflow() {
        let gm = create_guest_mem();
        let cmdline_address = GuestAddress(MEM_SIZE - 5);
        assert_eq!(
            Err(Error::CommandLineOverflow),
            load_cmdline(
                &gm,
                cmdline_address,
                CStr::from_bytes_with_nul(b"12345\0").unwrap()
            )
        );
    }

    #[test]
    fn cmdline_write_end() {
        let gm = create_guest_mem();
        let mut cmdline_address = GuestAddress(45);
        assert_eq!(
            Ok(()),
            load_cmdline(
                &gm,
                cmdline_address,
                CStr::from_bytes_with_nul(b"1234\0").unwrap()
            )
        );
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '1' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '2' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '3' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '4' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '\0' as u8);
    }

    // Elf64 image that prints hello world on x86_64.
    fn make_elf_bin() -> File {
        let elf_bytes = include_bytes!("test_elf.bin");
        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
        shm.set_size(elf_bytes.len() as u64)
            .expect("failed to set shared memory size");
        shm.write_all(elf_bytes)
            .expect("failed to write elf to shared memoy");
        shm.into()
    }

    fn mutate_elf_bin(mut f: &File, offset: u64, val: u8) {
        f.seek(SeekFrom::Start(offset))
            .expect("failed to seek file");
        f.write(&[val])
            .expect("failed to write mutated value to file");
    }

    #[test]
    fn load_elf() {
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut image = make_elf_bin();
        assert_eq!(Ok(16613), load_kernel(&gm, kernel_addr, &mut image));
    }

    #[test]
    fn bad_magic() {
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut bad_image = make_elf_bin();
        mutate_elf_bin(&bad_image, 0x1, 0x33);
        assert_eq!(
            Err(Error::InvalidElfMagicNumber),
            load_kernel(&gm, kernel_addr, &mut bad_image)
        );
    }

    #[test]
    fn bad_endian() {
        // Only little endian is supported
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut bad_image = make_elf_bin();
        mutate_elf_bin(&bad_image, 0x5, 2);
        assert_eq!(
            Err(Error::BigEndianElfOnLittle),
            load_kernel(&gm, kernel_addr, &mut bad_image)
        );
    }

    #[test]
    fn bad_phoff() {
        // program header has to be past the end of the elf header
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut bad_image = make_elf_bin();
        mutate_elf_bin(&bad_image, 0x20, 0x10);
        assert_eq!(
            Err(Error::InvalidProgramHeaderOffset),
            load_kernel(&gm, kernel_addr, &mut bad_image)
        );
    }
}
<commit_msg>kernel_loader: check phdr memory size addition<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::ffi::CStr;
use std::fmt::{self, Display};
use std::io::{Read, Seek, SeekFrom};
use std::mem;
use std::os::unix::io::AsRawFd;

use sys_util::{GuestAddress, GuestMemory};

#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
#[allow(clippy::all)]
mod elf;

#[derive(Debug, PartialEq)]
pub enum Error {
    BigEndianElfOnLittle,
    CommandLineCopy,
    CommandLineOverflow,
    InvalidElfMagicNumber,
    InvalidProgramHeaderSize,
    InvalidProgramHeaderOffset,
    InvalidProgramHeaderAddress,
    InvalidProgramHeaderMemSize,
    ReadElfHeader,
    ReadKernelImage,
    ReadProgramHeader,
    SeekKernelStart,
    SeekElfStart,
    SeekProgramHeader,
}
pub type Result<T> = std::result::Result<T, Error>;

impl std::error::Error for Error {}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        let description = match self {
            BigEndianElfOnLittle => "trying to load big-endian binary on little-endian machine",
            CommandLineCopy => "failed writing command line to guest memory",
            CommandLineOverflow => "command line overflowed guest memory",
            InvalidElfMagicNumber => "invalid Elf magic number",
            InvalidProgramHeaderSize => "invalid program header size",
            InvalidProgramHeaderOffset => "invalid program header offset",
            InvalidProgramHeaderAddress => "invalid Program Header Address",
            InvalidProgramHeaderMemSize => "invalid Program Header memory size",
            ReadElfHeader => "unable to read elf header",
            ReadKernelImage => "unable to read kernel image",
            ReadProgramHeader => "unable to read program header",
            SeekKernelStart => "unable to seek to kernel start",
            SeekElfStart => "unable to seek to elf start",
            SeekProgramHeader => "unable to seek to program header",
        };

        write!(f, "kernel loader: {}", description)
    }
}

/// Loads a kernel from a vmlinux elf image to a slice
///
/// # Arguments
///
/// * `guest_mem` - The guest memory region the kernel is written to.
/// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
/// * `kernel_image` - Input vmlinux image.
pub fn load_kernel<F>(
    guest_mem: &GuestMemory,
    kernel_start: GuestAddress,
    kernel_image: &mut F,
) -> Result<u64>
where
    F: Read + Seek + AsRawFd,
{
    let mut ehdr: elf::Elf64_Ehdr = Default::default();
    kernel_image
        .seek(SeekFrom::Start(0))
        .map_err(|_| Error::SeekElfStart)?;
    unsafe {
        // read_struct is safe when reading a POD struct.  It can be used and dropped without issue.
        sys_util::read_struct(kernel_image, &mut ehdr).map_err(|_| Error::ReadElfHeader)?;
    }

    // Sanity checks
    if ehdr.e_ident[elf::EI_MAG0 as usize] != elf::ELFMAG0 as u8
        || ehdr.e_ident[elf::EI_MAG1 as usize] != elf::ELFMAG1
        || ehdr.e_ident[elf::EI_MAG2 as usize] != elf::ELFMAG2
        || ehdr.e_ident[elf::EI_MAG3 as usize] != elf::ELFMAG3
    {
        return Err(Error::InvalidElfMagicNumber);
    }
    if ehdr.e_ident[elf::EI_DATA as usize] != elf::ELFDATA2LSB as u8 {
        return Err(Error::BigEndianElfOnLittle);
    }
    if ehdr.e_phentsize as usize != mem::size_of::<elf::Elf64_Phdr>() {
        return Err(Error::InvalidProgramHeaderSize);
    }
    if (ehdr.e_phoff as usize) < mem::size_of::<elf::Elf64_Ehdr>() {
        // If the program header is backwards, bail.
        return Err(Error::InvalidProgramHeaderOffset);
    }

    kernel_image
        .seek(SeekFrom::Start(ehdr.e_phoff))
        .map_err(|_| Error::SeekProgramHeader)?;
    let phdrs: Vec<elf::Elf64_Phdr> = unsafe {
        // Reading the structs is safe for a slice of POD structs.
        sys_util::read_struct_slice(kernel_image, ehdr.e_phnum as usize)
            .map_err(|_| Error::ReadProgramHeader)?
    };

    let mut kernel_end = 0;

    // Read in each section pointed to by the program headers.
    for phdr in &phdrs {
        if phdr.p_type != elf::PT_LOAD || phdr.p_filesz == 0 {
            continue;
        }

        kernel_image
            .seek(SeekFrom::Start(phdr.p_offset))
            .map_err(|_| Error::SeekKernelStart)?;

        let mem_offset = kernel_start
            .checked_add(phdr.p_paddr)
            .ok_or(Error::InvalidProgramHeaderAddress)?;
        guest_mem
            .read_to_memory(mem_offset, kernel_image, phdr.p_filesz as usize)
            .map_err(|_| Error::ReadKernelImage)?;

        kernel_end = mem_offset
            .offset()
            .checked_add(phdr.p_memsz)
            .ok_or(Error::InvalidProgramHeaderMemSize)?;
    }

    Ok(kernel_end)
}

/// Writes the command line string to the given memory slice.
///
/// # Arguments
///
/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
/// * `guest_addr` - The address in `guest_mem` at which to load the command line.
/// * `cmdline` - The kernel command line.
pub fn load_cmdline(
    guest_mem: &GuestMemory,
    guest_addr: GuestAddress,
    cmdline: &CStr,
) -> Result<()> {
    let len = cmdline.to_bytes().len();
    if len == 0 {
        return Ok(());
    }

    let end = guest_addr
        .checked_add(len as u64 + 1)
        .ok_or(Error::CommandLineOverflow)?; // Extra for null termination.
    if end > guest_mem.end_addr() {
        return Err(Error::CommandLineOverflow)?;
    }

    guest_mem
        .write_at_addr(cmdline.to_bytes_with_nul(), guest_addr)
        .map_err(|_| Error::CommandLineCopy)?;

    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::File;
    use std::io::Write;
    use sys_util::{GuestAddress, GuestMemory, SharedMemory};

    const MEM_SIZE: u64 = 0x8000;

    fn create_guest_mem() -> GuestMemory {
        GuestMemory::new(&vec![(GuestAddress(0x0), MEM_SIZE)]).unwrap()
    }

    #[test]
    fn cmdline_overflow() {
        let gm = create_guest_mem();
        let cmdline_address = GuestAddress(MEM_SIZE - 5);
        assert_eq!(
            Err(Error::CommandLineOverflow),
            load_cmdline(
                &gm,
                cmdline_address,
                CStr::from_bytes_with_nul(b"12345\0").unwrap()
            )
        );
    }

    #[test]
    fn cmdline_write_end() {
        let gm = create_guest_mem();
        let mut cmdline_address = GuestAddress(45);
        assert_eq!(
            Ok(()),
            load_cmdline(
                &gm,
                cmdline_address,
                CStr::from_bytes_with_nul(b"1234\0").unwrap()
            )
        );
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '1' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '2' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '3' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '4' as u8);
        cmdline_address = cmdline_address.unchecked_add(1);
        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
        assert_eq!(val, '\0' as u8);
    }

    // Elf64 image that prints hello world on x86_64.
    fn make_elf_bin() -> File {
        let elf_bytes = include_bytes!("test_elf.bin");
        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
        shm.set_size(elf_bytes.len() as u64)
            .expect("failed to set shared memory size");
        shm.write_all(elf_bytes)
            .expect("failed to write elf to shared memoy");
        shm.into()
    }

    fn mutate_elf_bin(mut f: &File, offset: u64, val: u8) {
        f.seek(SeekFrom::Start(offset))
            .expect("failed to seek file");
        f.write(&[val])
            .expect("failed to write mutated value to file");
    }

    #[test]
    fn load_elf() {
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut image = make_elf_bin();
        assert_eq!(Ok(16613), load_kernel(&gm, kernel_addr, &mut image));
    }

    #[test]
    fn bad_magic() {
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut bad_image = make_elf_bin();
        mutate_elf_bin(&bad_image, 0x1, 0x33);
        assert_eq!(
            Err(Error::InvalidElfMagicNumber),
            load_kernel(&gm, kernel_addr, &mut bad_image)
        );
    }

    #[test]
    fn bad_endian() {
        // Only little endian is supported
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut bad_image = make_elf_bin();
        mutate_elf_bin(&bad_image, 0x5, 2);
        assert_eq!(
            Err(Error::BigEndianElfOnLittle),
            load_kernel(&gm, kernel_addr, &mut bad_image)
        );
    }

    #[test]
    fn bad_phoff() {
        // program header has to be past the end of the elf header
        let gm = create_guest_mem();
        let kernel_addr = GuestAddress(0x0);
        let mut bad_image = make_elf_bin();
        mutate_elf_bin(&bad_image, 0x20, 0x10);
        assert_eq!(
            Err(Error::InvalidProgramHeaderOffset),
            load_kernel(&gm, kernel_addr, &mut bad_image)
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;

use hcore::service::ServiceGroup;

use census::{CensusGroup, CensusMember, CensusRing, ElectionStatus};
use manager::Sys;
use manager::service::{Cfg, Pkg, ServiceBind};

#[derive(Clone, Debug, Serialize)]
pub struct Binds<'a>(HashMap<String, BindGroup<'a>>);

impl<'a> Binds<'a> {
    fn new(bindings: &[ServiceBind], census: &'a CensusRing) -> Self {
        let mut map = HashMap::default();
        for bind in bindings {
            if let Some(group) = census.census_group_for(&bind.service_group) {
                map.insert(bind.name.to_string(), BindGroup::new(group));
            }
        }
        Binds(map)
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct BindGroup<'a> {
    members: Vec<SvcMember<'a>>,
}

impl<'a> BindGroup<'a> {
    fn new(group: &'a CensusGroup) -> Self {
        BindGroup { members: group.members().iter().map(|m| SvcMember(m)).collect() }
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct RenderContext<'a> {
    pub sys: &'a Sys,
    pub pkg: &'a Pkg,
    pub cfg: &'a Cfg,
    pub svc: Svc<'a>,
    pub bind: Binds<'a>,
}

impl<'a> RenderContext<'a> {
    pub fn new(service_group: &ServiceGroup,
               sys: &'a Sys,
               pkg: &'a Pkg,
               cfg: &'a Cfg,
               census: &'a CensusRing,
               bindings: &[ServiceBind])
               -> RenderContext<'a> {
        let census_group = census
            .census_group_for(&service_group)
            .expect("Census Group missing from list!");
        RenderContext {
            sys: sys,
            pkg: pkg,
            cfg: cfg,
            svc: Svc::new(census_group),
            bind: Binds::new(bindings, census),
        }
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct Svc<'a> {
    pub group: &'a ServiceGroup,
    pub election_is_running: bool,
    pub election_is_no_quorum: bool,
    pub election_is_finished: bool,
    pub update_election_is_running: bool,
    pub update_election_is_no_quorum: bool,
    pub update_election_is_finished: bool,
    pub me: SvcMember<'a>,
    pub members: Vec<SvcMember<'a>>,
    pub leader: Option<SvcMember<'a>>,
    pub update_leader: Option<SvcMember<'a>>,
}

impl<'a> Svc<'a> {
    fn new(census_group: &'a CensusGroup) -> Self {
        Svc {
            group: &census_group.service_group,
            election_is_running: census_group.election_status == ElectionStatus::ElectionInProgress,
            election_is_no_quorum: census_group.election_status == ElectionStatus::ElectionNoQuorum,
            election_is_finished: census_group.election_status == ElectionStatus::ElectionFinished,
            update_election_is_running: census_group.election_status ==
                                        ElectionStatus::ElectionInProgress,
            update_election_is_no_quorum: census_group.election_status ==
                                          ElectionStatus::ElectionNoQuorum,
            update_election_is_finished: census_group.election_status ==
                                         ElectionStatus::ElectionFinished,
            me: SvcMember(census_group.me().expect("Missing 'me'")),
            members: census_group
                .members()
                .iter()
                .map(|m| SvcMember(m))
                .collect(),
            leader: census_group.leader().map(|m| SvcMember(m)),
            update_leader: census_group.update_leader().map(|m| SvcMember(m)),
        }
    }
}

/// A friendly representation of a `CensusMember` to the templating system.
#[derive(Clone, Debug, Serialize)]
pub struct SvcMember<'a>(&'a CensusMember);
<commit_msg>Add Svc.first to templating/context<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;

use hcore::service::ServiceGroup;

use census::{CensusGroup, CensusMember, CensusRing, ElectionStatus};
use manager::Sys;
use manager::service::{Cfg, Pkg, ServiceBind};

#[derive(Clone, Debug, Serialize)]
pub struct Binds<'a>(HashMap<String, BindGroup<'a>>);

impl<'a> Binds<'a> {
    fn new(bindings: &[ServiceBind], census: &'a CensusRing) -> Self {
        let mut map = HashMap::default();
        for bind in bindings {
            if let Some(group) = census.census_group_for(&bind.service_group) {
                map.insert(bind.name.to_string(), BindGroup::new(group));
            }
        }
        Binds(map)
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct BindGroup<'a> {
    members: Vec<SvcMember<'a>>,
}

impl<'a> BindGroup<'a> {
    fn new(group: &'a CensusGroup) -> Self {
        BindGroup { members: group.members().iter().map(|m| SvcMember(m)).collect() }
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct RenderContext<'a> {
    pub sys: &'a Sys,
    pub pkg: &'a Pkg,
    pub cfg: &'a Cfg,
    pub svc: Svc<'a>,
    pub bind: Binds<'a>,
}

impl<'a> RenderContext<'a> {
    pub fn new(service_group: &ServiceGroup,
               sys: &'a Sys,
               pkg: &'a Pkg,
               cfg: &'a Cfg,
               census: &'a CensusRing,
               bindings: &[ServiceBind])
               -> RenderContext<'a> {
        let census_group = census
            .census_group_for(&service_group)
            .expect("Census Group missing from list!");
        RenderContext {
            sys: sys,
            pkg: pkg,
            cfg: cfg,
            svc: Svc::new(census_group),
            bind: Binds::new(bindings, census),
        }
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct Svc<'a> {
    pub group: &'a ServiceGroup,
    pub election_is_running: bool,
    pub election_is_no_quorum: bool,
    pub election_is_finished: bool,
    pub update_election_is_running: bool,
    pub update_election_is_no_quorum: bool,
    pub update_election_is_finished: bool,
    pub me: SvcMember<'a>,
    pub first: SvcMember<'a>,
    pub members: Vec<SvcMember<'a>>,
    pub leader: Option<SvcMember<'a>>,
    pub update_leader: Option<SvcMember<'a>>,
}

impl<'a> Svc<'a> {
    fn new(census_group: &'a CensusGroup) -> Self {
        let first = match census_group.leader() {
            Some(member) => SvcMember(member),
            None => SvcMember(census_group.members()[0]),
        };
        Svc {
            group: &census_group.service_group,
            election_is_running: census_group.election_status == ElectionStatus::ElectionInProgress,
            election_is_no_quorum: census_group.election_status == ElectionStatus::ElectionNoQuorum,
            election_is_finished: census_group.election_status == ElectionStatus::ElectionFinished,
            update_election_is_running: census_group.election_status ==
                                        ElectionStatus::ElectionInProgress,
            update_election_is_no_quorum: census_group.election_status ==
                                          ElectionStatus::ElectionNoQuorum,
            update_election_is_finished: census_group.election_status ==
                                         ElectionStatus::ElectionFinished,
            me: SvcMember(census_group.me().expect("Missing 'me'")),
            members: census_group
                .members()
                .iter()
                .map(|m| SvcMember(m))
                .collect(),
            leader: census_group.leader().map(|m| SvcMember(m)),
            first: first,
            update_leader: census_group.update_leader().map(|m| SvcMember(m)),
        }
    }
}

/// A friendly representation of a `CensusMember` to the templating system.
#[derive(Clone, Debug, Serialize)]
pub struct SvcMember<'a>(&'a CensusMember);
<|endoftext|>


<commit_before>mod protocols {
    extern crate pkg_config;

    use std::env;
    use std::fs;
    use std::path::PathBuf;
    use std::process::Command;

    pub fn generate_if_feature_enabled() {
        if env::var("CARGO_FEATURE_PROTOCOLS").is_ok() {
            generate_protocols();
        }
    }

    fn generate_protocols() {
        let prefix = match env::var("PROTOBUF_PREFIX").ok() {
            Some(prefix) => prefix,
            None => match pkg_config::get_variable("protobuf", "prefix") {
                Ok(prefix) => prefix,
                Err(msg) => panic!("Unable to locate protobuf, err={:?}", msg),
            },
        };

        let out_dir = r"src/message";
        let cmd = Command::new(format!("{}/bin/protoc", prefix))
            .arg("--rust_out")
            .arg(out_dir)
            .args(&protocol_files())
            .output();
        match cmd {
            Ok(out) => {
                if !out.status.success() {
                    panic!("{:?}", out)
                }
            }
            Err(e) => panic!("{}", e),
        }
    }

    fn protocol_files() -> Vec<PathBuf> {
        let mut files = vec![];
        for entry in fs::read_dir("protocols").unwrap() {
            let file = entry.unwrap();
            // skip vim temp files
            if file.file_name().to_str().unwrap().starts_with(".") {
                continue;
            }
            if file.metadata().unwrap().is_file() {
                files.push(file.path());
            }
        }
        files
    }
}
<commit_msg>Delete libbuild-protocols.rs build instructions<commit_after><|endoftext|>


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

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::UIEventBinding;
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
use dom::bindings::codegen::InheritTypes::{EventCast, UIEventDerived};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::global;
use dom::bindings::js::{MutNullableJS, JSRef, RootedReference, Temporary, OptionalSettable};

use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::event::{Event, EventTypeId, UIEventTypeId};
use dom::window::Window;
use servo_util::str::DOMString;

use std::cell::Cell;
use std::default::Default;

#[dom_struct]
pub struct UIEvent {
    event: Event,
    view: MutNullableJS<Window>,
    detail: Cell<i32>
}

impl UIEventDerived for Event {
    fn is_uievent(&self) -> bool {
        *self.type_id() == UIEventTypeId
    }
}

impl UIEvent {
    pub fn new_inherited(type_id: EventTypeId) -> UIEvent {
        UIEvent {
            event: Event::new_inherited(type_id),
            view: Default::default(),
            detail: Cell::new(0),
        }
    }

    pub fn new_uninitialized(window: JSRef<Window>) -> Temporary<UIEvent> {
        reflect_dom_object(box UIEvent::new_inherited(UIEventTypeId),
                           &global::Window(window),
                           UIEventBinding::Wrap)
    }

    pub fn new(window: JSRef<Window>,
               type_: DOMString,
               can_bubble: bool,
               cancelable: bool,
               view: Option<JSRef<Window>>,
               detail: i32) -> Temporary<UIEvent> {
        let ev = UIEvent::new_uninitialized(window).root();
        ev.InitUIEvent(type_, can_bubble, cancelable, view, detail);
        Temporary::from_rooted(*ev)
    }

    pub fn Constructor(global: &GlobalRef,
                       type_: DOMString,
                       init: &UIEventBinding::UIEventInit) -> Fallible<Temporary<UIEvent>> {
        let event = UIEvent::new(global.as_window(), type_,
                                 init.parent.bubbles, init.parent.cancelable,
                                 init.view.root_ref(), init.detail);
        Ok(event)
    }

    #[inline]
    pub fn event<'a>(&'a self) -> &'a Event {
        &self.event
    }
}

impl<'a> UIEventMethods for JSRef<'a, UIEvent> {
    fn GetView(self) -> Option<Temporary<Window>> {
        self.view.get()
    }

    fn Detail(self) -> i32 {
        self.detail.get()
    }

    fn InitUIEvent(self,
                   type_: DOMString,
                   can_bubble: bool,
                   cancelable: bool,
                   view: Option<JSRef<Window>>,
                   detail: i32) {
        let event: JSRef<Event> = EventCast::from_ref(self);
        if event.dispatching() {
            return;
        }

        event.InitEvent(type_, can_bubble, cancelable);
        self.view.assign(view);
        self.detail.set(detail);
    }
}

impl Reflectable for UIEvent {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.event.reflector()
    }
}
<commit_msg>Remove UIEvent.event().<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::UIEventBinding;
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
use dom::bindings::codegen::InheritTypes::{EventCast, UIEventDerived};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::global;
use dom::bindings::js::{MutNullableJS, JSRef, RootedReference, Temporary, OptionalSettable};

use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::event::{Event, EventTypeId, UIEventTypeId};
use dom::window::Window;
use servo_util::str::DOMString;

use std::cell::Cell;
use std::default::Default;

#[dom_struct]
pub struct UIEvent {
    event: Event,
    view: MutNullableJS<Window>,
    detail: Cell<i32>
}

impl UIEventDerived for Event {
    fn is_uievent(&self) -> bool {
        *self.type_id() == UIEventTypeId
    }
}

impl UIEvent {
    pub fn new_inherited(type_id: EventTypeId) -> UIEvent {
        UIEvent {
            event: Event::new_inherited(type_id),
            view: Default::default(),
            detail: Cell::new(0),
        }
    }

    pub fn new_uninitialized(window: JSRef<Window>) -> Temporary<UIEvent> {
        reflect_dom_object(box UIEvent::new_inherited(UIEventTypeId),
                           &global::Window(window),
                           UIEventBinding::Wrap)
    }

    pub fn new(window: JSRef<Window>,
               type_: DOMString,
               can_bubble: bool,
               cancelable: bool,
               view: Option<JSRef<Window>>,
               detail: i32) -> Temporary<UIEvent> {
        let ev = UIEvent::new_uninitialized(window).root();
        ev.InitUIEvent(type_, can_bubble, cancelable, view, detail);
        Temporary::from_rooted(*ev)
    }

    pub fn Constructor(global: &GlobalRef,
                       type_: DOMString,
                       init: &UIEventBinding::UIEventInit) -> Fallible<Temporary<UIEvent>> {
        let event = UIEvent::new(global.as_window(), type_,
                                 init.parent.bubbles, init.parent.cancelable,
                                 init.view.root_ref(), init.detail);
        Ok(event)
    }
}

impl<'a> UIEventMethods for JSRef<'a, UIEvent> {
    fn GetView(self) -> Option<Temporary<Window>> {
        self.view.get()
    }

    fn Detail(self) -> i32 {
        self.detail.get()
    }

    fn InitUIEvent(self,
                   type_: DOMString,
                   can_bubble: bool,
                   cancelable: bool,
                   view: Option<JSRef<Window>>,
                   detail: i32) {
        let event: JSRef<Event> = EventCast::from_ref(self);
        if event.dispatching() {
            return;
        }

        event.InitEvent(type_, can_bubble, cancelable);
        self.view.assign(view);
        self.detail.set(detail);
    }
}

impl Reflectable for UIEvent {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.event.reflector()
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::store::Store;
use libimagerror::trace::trace_error;
use std::error::Error;
use std::ops::Deref;
use std::ops::DerefMut;

use ruru::{Class, Object, AnyObject, Boolean, RString, VM, Hash, NilClass, VerifiedObject};

use ruby_utils::IntoToml;
use toml_utils::IntoRuby;
use util::Wrap;
use util::Unwrap;

use storeid::RStoreId;
use entry::RFileLockEntry;
use cache::StoreHandle;

wrappable_struct!(StoreHandle, StoreWrapper, STORE_WRAPPER);
class!(RStore);
impl_wrap!(StoreHandle, STORE_WRAPPER);
impl_unwrap!(RStore, StoreHandle, STORE_WRAPPER);
impl_verified_object!(RStore);

macro_rules! call_on_store_by_handle {
    {
        $store_handle:ident named $name:ident inside $operation:block
    }=> {{
        call_on_store_by_handle! {
            $store_handle
            named $name
            inside $operation
            on fail return NilClass::new().to_any_object()
        }
    }};

    {
        $store_handle:ident named $name:ident inside $operation:block on fail return $ex:expr
    } => {{
        use cache::RUBY_STORE_CACHE;

        let arc = RUBY_STORE_CACHE.clone();
        {
            let lock = arc.lock();
            match lock {
                Ok(mut hm) => {
                    match hm.get($store_handle) {
                        Some($name) => { $operation },
                        None => {
                            VM::raise(Class::from_existing("RuntimeError"),
                                    "Tried to operate on non-existing object");
                            $ex
                        }
                    }
                },
                Err(e) => {
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                    $ex
                }
            }
        }
    }};
}

macro_rules! call_on_store {
    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident
        operation $operation:block
    } => {
        call_on_store! {
            $store_name <- $itself wrapped inside $wrapper,
            $fle_name <- fetch $fle_handle_name,
            operation $operation,
            on fail return NilClass::new()
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside {
                let $fle_name = match $store_name.get($fle_handle_name) {
                    Ok(Some(fle)) => fle,
                    Ok(None) => {
                        VM::raise(Class::from_existing("RuntimeError"), "Obj does not exist");
                        return $fail_expr
                    },
                    Err(e) => {
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        return $fail_expr
                    },
                };
                $operation
            }
            on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside $operation on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $block
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! { handle named $name inside $operation }
    };
}

methods!(
    RStore,
    itself,

    // Create an FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On failure: Nil
    // On error: Nil + Exception
    //
    fn create(id: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Retrieve an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On error: Nil + Exception
    //
    fn retrieve(id: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Get an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success, if there is some: A RFileLockEntry
    // On success, if there is none: Nil
    // On error: Nil + Exception
    //
    fn get(sid: RStoreId) -> AnyObject {
        use entry::FileLockEntryHandle;
        let sid = typecheck!(sid or return any NilClass::new()).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                match store.get(sid.clone()) {
                    Err(e) => {
                        trace_error(&e);
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        NilClass::new().to_any_object()
                    },
                    Ok(None) => NilClass::new().to_any_object(),
                    Ok(Some(entry)) => {
                        // Take the location (StoreId) of the entry (we know it exists... so this
                        // is fine) and wrap it into a RFileLockEntry which is then returned to the
                        // user (as handle)
                        let sid = entry.get_location().clone();
                        let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
                        FileLockEntryHandle::new(store_handle, sid).wrap()
                    },
                }
            },
            on fail return NilClass::new().to_any_object()
        }
    }

    // Get all FileLockEntry of a module from the store
    //
    // # Returns:
    //
    // On success: A Array[RFileLockEntry]
    // On error: Nil + Exception
    //
    fn retrieve_for_module(name: RString) -> AnyObject {
        unimplemented!()
    }

    // Update a FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn update(fle: RFileLockEntry) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.update(real_fle) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Delete a FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn delete(sid: RStoreId) -> NilClass {
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.delete(sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, keep the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_to(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_to(&real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, move the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_as(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_as(real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Move one entry in the store to another place, by its ID
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn move_by_id(old: RStoreId, nw: RStoreId) -> NilClass {
        let old = typecheck!(old).unwrap().clone();
        let nw  = typecheck!(nw).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.move_by_id(old, nw) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Get the path of the store object
    //
    // # Returns:
    //
    // A RString
    //
    fn path() -> RString {
        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                store.path()
                    .clone()
                    .to_str()
                    .map(RString::new)
                    .unwrap_or(RString::new(""))
            },
            on fail return RString::new("")
        }
    }

);

pub fn setup() {
    unimplemented!()
}
<commit_msg>Impl Store::retrieve() interface<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::store::Store;
use libimagerror::trace::trace_error;
use std::error::Error;
use std::ops::Deref;
use std::ops::DerefMut;

use ruru::{Class, Object, AnyObject, Boolean, RString, VM, Hash, NilClass, VerifiedObject};

use ruby_utils::IntoToml;
use toml_utils::IntoRuby;
use util::Wrap;
use util::Unwrap;

use storeid::RStoreId;
use entry::RFileLockEntry;
use cache::StoreHandle;

wrappable_struct!(StoreHandle, StoreWrapper, STORE_WRAPPER);
class!(RStore);
impl_wrap!(StoreHandle, STORE_WRAPPER);
impl_unwrap!(RStore, StoreHandle, STORE_WRAPPER);
impl_verified_object!(RStore);

macro_rules! call_on_store_by_handle {
    {
        $store_handle:ident named $name:ident inside $operation:block
    }=> {{
        call_on_store_by_handle! {
            $store_handle
            named $name
            inside $operation
            on fail return NilClass::new().to_any_object()
        }
    }};

    {
        $store_handle:ident named $name:ident inside $operation:block on fail return $ex:expr
    } => {{
        use cache::RUBY_STORE_CACHE;

        let arc = RUBY_STORE_CACHE.clone();
        {
            let lock = arc.lock();
            match lock {
                Ok(mut hm) => {
                    match hm.get($store_handle) {
                        Some($name) => { $operation },
                        None => {
                            VM::raise(Class::from_existing("RuntimeError"),
                                    "Tried to operate on non-existing object");
                            $ex
                        }
                    }
                },
                Err(e) => {
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                    $ex
                }
            }
        }
    }};
}

macro_rules! call_on_store {
    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident
        operation $operation:block
    } => {
        call_on_store! {
            $store_name <- $itself wrapped inside $wrapper,
            $fle_name <- fetch $fle_handle_name,
            operation $operation,
            on fail return NilClass::new()
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        $fle_name:ident <- fetch $fle_handle_name:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside {
                let $fle_name = match $store_name.get($fle_handle_name) {
                    Ok(Some(fle)) => fle,
                    Ok(None) => {
                        VM::raise(Class::from_existing("RuntimeError"), "Obj does not exist");
                        return $fail_expr
                    },
                    Err(e) => {
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        return $fail_expr
                    },
                };
                $operation
            }
            on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $operation:block,
        on fail return $fail_expr:expr
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! {
            handle named $store_name inside $operation on fail return $fail_expr
        }
    };

    {
        $store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
        operation $block
    } => {
        let handle = $itself.get_data(&*$wrapper);
        call_on_store_by_handle! { handle named $name inside $operation }
    };
}

methods!(
    RStore,
    itself,

    // Create an FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On failure: Nil
    // On error: Nil + Exception
    //
    fn create(id: RStoreId) -> AnyObject {
        unimplemented!()
    }

    // Retrieve an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: A RFileLockEntry
    // On error: Nil + Exception
    //
    fn retrieve(id: RStoreId) -> AnyObject {
        use entry::FileLockEntryHandle;
        let sid = typecheck!(id or return any NilClass::new()).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                match store.retrieve(sid.clone()) {
                    Err(e) => {
                        trace_error(&e);
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        NilClass::new().to_any_object()
                    },
                    Ok(entry) => {
                        // Take the location (StoreId) of the entry (we know it exists... so this
                        // is fine) and wrap it into a RFileLockEntry which is then returned to the
                        // user (as handle)
                        let sid = entry.get_location().clone();
                        let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
                        FileLockEntryHandle::new(store_handle, sid).wrap()
                    },
                }
            },
            on fail return NilClass::new().to_any_object()
        }
    }

    // Get an FileLockEntry from the store
    //
    // # Returns:
    //
    // On success, if there is some: A RFileLockEntry
    // On success, if there is none: Nil
    // On error: Nil + Exception
    //
    fn get(sid: RStoreId) -> AnyObject {
        use entry::FileLockEntryHandle;
        let sid = typecheck!(sid or return any NilClass::new()).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                match store.get(sid.clone()) {
                    Err(e) => {
                        trace_error(&e);
                        VM::raise(Class::from_existing("RuntimeError"), e.description());
                        NilClass::new().to_any_object()
                    },
                    Ok(None) => NilClass::new().to_any_object(),
                    Ok(Some(entry)) => {
                        // Take the location (StoreId) of the entry (we know it exists... so this
                        // is fine) and wrap it into a RFileLockEntry which is then returned to the
                        // user (as handle)
                        let sid = entry.get_location().clone();
                        let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
                        FileLockEntryHandle::new(store_handle, sid).wrap()
                    },
                }
            },
            on fail return NilClass::new().to_any_object()
        }
    }

    // Get all FileLockEntry of a module from the store
    //
    // # Returns:
    //
    // On success: A Array[RFileLockEntry]
    // On error: Nil + Exception
    //
    fn retrieve_for_module(name: RString) -> AnyObject {
        unimplemented!()
    }

    // Update a FileLockEntry in the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn update(fle: RFileLockEntry) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.update(real_fle) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Delete a FileLockEntry from the store
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn delete(sid: RStoreId) -> NilClass {
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.delete(sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, keep the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_to(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_to(&real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Save a FileLockEntry in a new path inside the store, move the RFileLockEntry
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn save_as(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
        let fle = typecheck!(fle).unwrap().clone();
        let sid = typecheck!(sid).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            real_fle <- fetch fle,
            operation {
                if let Err(e) = store.save_as(real_fle, sid) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Move one entry in the store to another place, by its ID
    //
    // # Returns:
    //
    // On success: Nil
    // On error: Nil + Exception
    //
    fn move_by_id(old: RStoreId, nw: RStoreId) -> NilClass {
        let old = typecheck!(old).unwrap().clone();
        let nw  = typecheck!(nw).unwrap().clone();

        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                if let Err(e) = store.move_by_id(old, nw) {
                    trace_error(&e);
                    VM::raise(Class::from_existing("RuntimeError"), e.description());
                }
                NilClass::new()
            },
            on fail return NilClass::new()
        }
    }

    // Get the path of the store object
    //
    // # Returns:
    //
    // A RString
    //
    fn path() -> RString {
        call_on_store! {
            store <- itself wrapped inside STORE_WRAPPER,
            operation {
                store.path()
                    .clone()
                    .to_str()
                    .map(RString::new)
                    .unwrap_or(RString::new(""))
            },
            on fail return RString::new("")
        }
    }

);

pub fn setup() {
    unimplemented!()
}
<|endoftext|>


<commit_before>extern crate libc;

use api::ErrorCode;
use commands::agent::RouteCommand;
use commands::{Command, CommandExecutor};
use errors::ToErrorCode;
use utils::ctypes;

use self::libc::c_char;

#[no_mangle]
pub fn indy_auth_pack_message(
    command_handle: i32,
    wallet_handle: i32,
    message: *const c_char,
    recv_keys: *const c_char,
    my_vk: *const c_char,
    cb: Option<extern "C" fn(xcommand_handle: i32, err: ErrorCode, ames: *const c_char)>,
) -> ErrorCode {
    trace!("indy_auth_pack_message: >>> wallet_handle: {:?}, message: {:?}, recv_keys: {:?}, my_vk: {:?}",
           wallet_handle, message, recv_keys, my_vk);

    check_useful_c_str!(message, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(recv_keys, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(my_vk, ErrorCode::CommonInvalidParam5);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6);

    trace!("indy_auth_pack_message: entities >>> wallet_handle: {:?}, message: {:?}, recv_keys: {:?}, my_vk: {:?}",
           wallet_handle, message, recv_keys, my_vk);

    let result = CommandExecutor::instance().send(Command::Route(RouteCommand::AuthPackMessage(
        message,
        recv_keys,
        my_vk,
        wallet_handle,
        Box::new(move |result| {
            let (err, ames) = result_to_err_code_1!(result, String::new());
            trace!(
                "indy_auth_pack_message: cb command_handle: {:?}, err: {:?}, ames: {:?}",
                command_handle,
                err,
                ames
            );
            let ames = ctypes::string_to_cstring(ames);
            cb(command_handle, err, ames.as_ptr())
        }),
    )));

    let res = result_to_err_code!(result);

    trace!("indy_auth_pack_message: <<< res: {:?}", res);

    res
}

#[no_mangle]
pub fn indy_anon_pack_message(
    command_handle: i32,
    message: *const c_char,
    recv_keys: *const c_char,
    cb: Option<extern "C" fn(xcommand_handle: i32, err: ErrorCode, ames: *const c_char)>,
) -> ErrorCode {
    trace!(
        "indy_anon_pack_message: >>> message: {:?}, recv_keys: {:?}",
        message,
        recv_keys
    );

    check_useful_c_str!(message, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(recv_keys, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    trace!(
        "indy_anon_pack_message: entities >>> message: {:?}, recv_keys: {:?}",
        message,
        recv_keys
    );

    let result = CommandExecutor::instance().send(Command::Route(RouteCommand::AnonPackMessage(
        message,
        recv_keys,
        Box::new(move |result| {
            let (err, ames) = result_to_err_code_1!(result, String::new());
            trace!(
                "indy_anon_pack_message: cb command_handle: {:?}, err: {:?}, ames: {:?}",
                command_handle,
                err,
                ames
            );
            let verkey = ctypes::string_to_cstring(ames);
            cb(command_handle, err, verkey.as_ptr())
        }),
    )));

    let res = result_to_err_code!(result);

    trace!("indy_anon_pack_message: <<< res: {:?}", res);

    res
}

//update function to return key used
#[no_mangle]
pub fn indy_unpack_message(
    command_handle: i32,
    wallet_handle: i32,
    ames_json: *const c_char,
    my_vk: *const c_char,
    cb: Option<
        extern "C" fn(
            xcommand_handle: i32,
            err: ErrorCode,
            plaintext: *const c_char,
            sender_vk: *const c_char,
        ),
    >,
) -> ErrorCode {
    trace!(
        "indy_unpack_message: >>> wallet_handle: {:?}, ames: {:?}, my_vk: {:?}",
        wallet_handle,
        ames_json,
        my_vk
    );

    check_useful_c_str!(ames_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(my_vk, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    trace!(
        "indy_unpack_message: entities >>> wallet_handle: {:?}, ames: {:?}, my_vk: {:?}",
        wallet_handle,
        ames_json,
        my_vk
    );

    let result = CommandExecutor::instance().send(Command::Route(RouteCommand::UnpackMessage(
        ames_json,
        my_vk,
        wallet_handle,
        Box::new(move |result| {
            let (err, plaintext, sender_vk) =
                result_to_err_code_2!(result, String::new(), String::new());
            trace!(
                "indy_unpack_message: cb command_handle: {:?}, err: {:?}, plaintext: {:?}",
                command_handle,
                err,
                plaintext
            );
            let plaintext = ctypes::string_to_cstring(plaintext);
            let sender_vk = ctypes::string_to_cstring(sender_vk);
            cb(command_handle, err, plaintext.as_ptr(), sender_vk.as_ptr())
        }),
    )));

    let res = result_to_err_code!(result);

    trace!("indy_unpack_message: <<< res: {:?}", res);

    res
}
<commit_msg>refactored API layer<commit_after>extern crate libc;

use api::ErrorCode;
use commands::agent::RouteCommand;
use commands::{Command, CommandExecutor};
use errors::ToErrorCode;
use utils::ctypes;

use self::libc::c_char;

#[no_mangle]
pub fn indy_auth_pack_message(
    command_handle: i32,
    wallet_handle: i32,
    message: *const c_char,
    receiver_keys: *const c_char,
    sender_verkey: *const c_char,
    cb: Option<extern "C" fn(xcommand_handle: i32, err: ErrorCode, jwe: *const c_char)>,
) -> ErrorCode {
    trace!("indy_auth_pack_message: >>> wallet_handle: {:?}, message: {:?}, recv_keys: {:?}, my_vk: {:?}",
           wallet_handle, message, receiver_keys, sender_verkey);

    check_useful_c_str!(message, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(recv_keys, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(my_vk, ErrorCode::CommonInvalidParam5);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6);

    trace!("indy_auth_pack_message: entities >>> wallet_handle: {:?}, message: {:?}, recv_keys: {:?}, my_vk: {:?}",
           wallet_handle, message, receiver_keys, sender_verkey);

    let result = CommandExecutor::instance().send(Command::Route(RouteCommand::AuthPackMessage(
        message,
        recveiver_keys,
        sender_verkey,
        wallet_handle,
        Box::new(move |result| {
            let (err, jwe) = result_to_err_code_1!(result, String::new());
            trace!(
                "indy_auth_pack_message: cb command_handle: {:?}, err: {:?}, jwe: {:?}",
                command_handle,
                err,
                jwe
            );
            let jwe = ctypes::string_to_cstring(jwe);
            cb(command_handle, err, jwe.as_ptr())
        }),
    )));

    let res = result_to_err_code!(result);

    trace!("indy_auth_pack_message: <<< res: {:?}", res);

    res
}

#[no_mangle]
pub fn indy_anon_pack_message(
    command_handle: i32,
    message: *const c_char,
    recveiver_keys: *const c_char,
    cb: Option<extern "C" fn(xcommand_handle: i32, err: ErrorCode, jwe: *const c_char)>,
) -> ErrorCode {
    trace!(
        "indy_anon_pack_message: >>> message: {:?}, recv_keys: {:?}",
        message,
        recveiver_keys
    );

    check_useful_c_str!(message, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(recv_keys, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    trace!(
        "indy_anon_pack_message: entities >>> message: {:?}, recv_keys: {:?}",
        message,
        recveiver_keys
    );

    let result = CommandExecutor::instance().send(Command::Route(RouteCommand::AnonPackMessage(
        message,
        recveiver_keys,
        Box::new(move |result| {
            let (err, jwe) = result_to_err_code_1!(result, String::new());
            trace!(
                "indy_anon_pack_message: cb command_handle: {:?}, err: {:?}, jwe: {:?}",
                command_handle,
                err,
                jwe
            );
            let verkey = ctypes::string_to_cstring(jwe);
            cb(command_handle, err, verkey.as_ptr())
        }),
    )));

    let res = result_to_err_code!(result);

    trace!("indy_anon_pack_message: <<< res: {:?}", res);

    res
}

//update function to return key used
#[no_mangle]
pub fn indy_unpack_message(
    command_handle: i32,
    wallet_handle: i32,
    jwe: *const c_char,
    sender_verkey: *const c_char,
    cb: Option<
        extern "C" fn(
            xcommand_handle: i32,
            err: ErrorCode,
            plaintext: *const c_char,
            sender_vk: *const c_char,
        ),
    >,
) -> ErrorCode {
    trace!(
        "indy_unpack_message: >>> wallet_handle: {:?}, jwe: {:?}, my_vk: {:?}",
        wallet_handle,
        jwe,
        sender_verkey
    );

    check_useful_c_str!(jwe_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(my_vk, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    trace!(
        "indy_unpack_message: entities >>> wallet_handle: {:?}, jwe: {:?}, my_vk: {:?}",
        wallet_handle,
        jwe,
        sender_verkey
    );

    let result = CommandExecutor::instance().send(Command::Route(RouteCommand::UnpackMessage(
        jwe,
        sender_verkey,
        wallet_handle,
        Box::new(move |result| {
            let (err, plaintext, sender_vk) =
                result_to_err_code_2!(result, String::new(), String::new());
            trace!(
                "indy_unpack_message: cb command_handle: {:?}, err: {:?}, plaintext: {:?}",
                command_handle,
                err,
                plaintext
            );
            let plaintext = ctypes::string_to_cstring(plaintext);
            let sender_vk = ctypes::string_to_cstring(sender_vk);
            cb(command_handle, err, plaintext.as_ptr(), sender_vk.as_ptr())
        }),
    )));

    let res = result_to_err_code!(result);

    trace!("indy_unpack_message: <<< res: {:?}", res);

    res
}
<|endoftext|>


<commit_before>//! The SQLite backend
use byteorder::NativeEndian;

use super::connection::SqliteValue;
use super::query_builder::SqliteQueryBuilder;
use crate::backend::*;
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::sql_types::TypeMetadata;

/// The SQLite backend
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Sqlite;

/// Determines how a bind parameter is given to SQLite
///
/// Diesel deals with bind parameters after serialization as opaque blobs of
/// bytes. However, SQLite instead has several functions where it expects the
/// relevant C types.
///
/// The variants of this struct determine what bytes are expected from
/// `ToSql` impls.
#[allow(missing_debug_implementations)]
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
pub enum SqliteType {
    /// Bind using `sqlite3_bind_blob`
    Binary,
    /// Bind using `sqlite3_bind_text`
    Text,
    /// `bytes` should contain an `f32`
    Float,
    /// `bytes` should contain an `f64`
    Double,
    /// `bytes` should contain an `i16`
    SmallInt,
    /// `bytes` should contain an `i32`
    Integer,
    /// `bytes` should contain an `i64`
    Long,
}

impl Backend for Sqlite {
    type QueryBuilder = SqliteQueryBuilder;
    type BindCollector = RawBytesBindCollector<Sqlite>;
    type ByteOrder = NativeEndian;
}

impl<'a> HasRawValue<'a> for Sqlite {
    type RawValue = &'a SqliteValue;
}

impl TypeMetadata for Sqlite {
    type TypeMetadata = SqliteType;
    type MetadataLookup = ();
}

impl SupportsDefaultKeyword for Sqlite {}
impl SupportsReturningClause for Sqlite {}
impl SupportsOnConflictClause for Sqlite {}
impl UsesAnsiSavepointSyntax for Sqlite {}
<commit_msg>Revert "Implement DefaultKeyword for Sqlite"<commit_after>//! The SQLite backend
use byteorder::NativeEndian;

use super::connection::SqliteValue;
use super::query_builder::SqliteQueryBuilder;
use crate::backend::*;
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::sql_types::TypeMetadata;

/// The SQLite backend
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Sqlite;

/// Determines how a bind parameter is given to SQLite
///
/// Diesel deals with bind parameters after serialization as opaque blobs of
/// bytes. However, SQLite instead has several functions where it expects the
/// relevant C types.
///
/// The variants of this struct determine what bytes are expected from
/// `ToSql` impls.
#[allow(missing_debug_implementations)]
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
pub enum SqliteType {
    /// Bind using `sqlite3_bind_blob`
    Binary,
    /// Bind using `sqlite3_bind_text`
    Text,
    /// `bytes` should contain an `f32`
    Float,
    /// `bytes` should contain an `f64`
    Double,
    /// `bytes` should contain an `i16`
    SmallInt,
    /// `bytes` should contain an `i32`
    Integer,
    /// `bytes` should contain an `i64`
    Long,
}

impl Backend for Sqlite {
    type QueryBuilder = SqliteQueryBuilder;
    type BindCollector = RawBytesBindCollector<Sqlite>;
    type ByteOrder = NativeEndian;
}

impl<'a> HasRawValue<'a> for Sqlite {
    type RawValue = &'a SqliteValue;
}

impl TypeMetadata for Sqlite {
    type TypeMetadata = SqliteType;
    type MetadataLookup = ();
}

impl SupportsReturningClause for Sqlite {}
impl SupportsOnConflictClause for Sqlite {}
impl UsesAnsiSavepointSyntax for Sqlite {}
<|endoftext|>


<commit_before>use std::ops::DerefMut;

use runtime::Runtime;
use error::RuntimeError;
use error::RuntimeErrorKind;

use libimagstore::store::FileLockEntry;
use libimagstore::store::Entry;

pub type EditResult<T> = Result<T, RuntimeError>;

pub trait Edit {
    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()>;
}

impl Edit for Entry {

    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
        edit_in_tmpfile(rt, self.get_content_mut())
            .map(|_| ())
    }

}

impl<'a> Edit for FileLockEntry<'a> {

    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
        self.deref_mut().edit_content(rt)
    }

}

pub fn edit_in_tmpfile(rt: &Runtime, s: &mut String) -> EditResult<()> {
    use tempfile::NamedTempFile;
    use std::io::Seek;
    use std::io::Read;
    use std::io::SeekFrom;
    use std::io::Write;

    let file      = try!(NamedTempFile::new());
    let file_path = file.path();
    let mut file  = try!(file.reopen());

    file.write_all(&s.clone().into_bytes()[..]);

    try!(file.sync_data());

    if let Some(mut editor) = rt.editor() {
        let exit_status = editor.arg(file_path).status();

        match exit_status.map(|s| s.success()) {
            Ok(true)  => {
                file.sync_data()
                    .and_then(|_| file.seek(SeekFrom::Start(0)))
                    .and_then(|_| file.read_to_string(s))
                    .map(|_| ())
                    .map_err(|e| RuntimeError::new(RuntimeErrorKind::IOError, Some(Box::new(e))))
            },
            Ok(false) => Err(RuntimeError::new(RuntimeErrorKind::ProcessExitFailure, None)),
            Err(e)    => Err(RuntimeError::new(RuntimeErrorKind::IOError, Some(Box::new(e)))),
        }
    } else {
        Err(RuntimeError::new(RuntimeErrorKind::Instantiate, None))
    }
}
<commit_msg>Make result used by try!()ing<commit_after>use std::ops::DerefMut;

use runtime::Runtime;
use error::RuntimeError;
use error::RuntimeErrorKind;

use libimagstore::store::FileLockEntry;
use libimagstore::store::Entry;

pub type EditResult<T> = Result<T, RuntimeError>;

pub trait Edit {
    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()>;
}

impl Edit for Entry {

    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
        edit_in_tmpfile(rt, self.get_content_mut())
            .map(|_| ())
    }

}

impl<'a> Edit for FileLockEntry<'a> {

    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
        self.deref_mut().edit_content(rt)
    }

}

pub fn edit_in_tmpfile(rt: &Runtime, s: &mut String) -> EditResult<()> {
    use tempfile::NamedTempFile;
    use std::io::Seek;
    use std::io::Read;
    use std::io::SeekFrom;
    use std::io::Write;

    let file      = try!(NamedTempFile::new());
    let file_path = file.path();
    let mut file  = try!(file.reopen());

    try!(file.write_all(&s.clone().into_bytes()[..]));
    try!(file.sync_data());

    if let Some(mut editor) = rt.editor() {
        let exit_status = editor.arg(file_path).status();

        match exit_status.map(|s| s.success()) {
            Ok(true)  => {
                file.sync_data()
                    .and_then(|_| file.seek(SeekFrom::Start(0)))
                    .and_then(|_| file.read_to_string(s))
                    .map(|_| ())
                    .map_err(|e| RuntimeError::new(RuntimeErrorKind::IOError, Some(Box::new(e))))
            },
            Ok(false) => Err(RuntimeError::new(RuntimeErrorKind::ProcessExitFailure, None)),
            Err(e)    => Err(RuntimeError::new(RuntimeErrorKind::IOError, Some(Box::new(e)))),
        }
    } else {
        Err(RuntimeError::new(RuntimeErrorKind::Instantiate, None))
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Poisson distribution.

use rand::Rng;
use crate::{Distribution, Cauchy, Standard};
use crate::utils::{log_gamma, Float};

/// The Poisson distribution `Poisson(lambda)`.
///
/// This distribution has a density function:
/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand_distr::{Poisson, Distribution};
///
/// let poi = Poisson::new(2.0).unwrap();
/// let v: u64 = poi.sample(&mut rand::thread_rng());
/// println!("{} is from a Poisson(2) distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Poisson<N> {
    lambda: N,
    // precalculated values
    exp_lambda: N,
    log_lambda: N,
    sqrt_2lambda: N,
    magic_val: N,
}

/// Error type returned from `Poisson::new`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
    /// `lambda <= 0` or `nan`.
    ShapeTooSmall,
}

impl<N: Float> Poisson<N> {
    /// Construct a new `Poisson` with the given shape parameter
    /// `lambda`.
    pub fn new(lambda: N) -> Result<Poisson<N>, Error> {
        if !(lambda > N::from(0.0)) {
            return Err(Error::ShapeTooSmall);
        }
        let log_lambda = lambda.ln();
        Ok(Poisson {
            lambda,
            exp_lambda: (-lambda).exp(),
            log_lambda,
            sqrt_2lambda: (N::from(2.0) * lambda).sqrt(),
            magic_val: lambda * log_lambda - log_gamma(N::from(1.0) + lambda),
        })
    }
}

impl<N: Float> Distribution<N> for Poisson<N>
where Standard: Distribution<N>
{
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N {
        // using the algorithm from Numerical Recipes in C

        // for low expected values use the Knuth method
        if self.lambda < N::from(12.0) {
            let mut result = N::from(0.);
            let mut p = N::from(1.0);
            while p > self.exp_lambda {
                p *= rng.gen::<N>();
                result += N::from(1.);
            }
            result - N::from(1.)
        }
        // high expected values - rejection method
        else {
            // we use the Cauchy distribution as the comparison distribution
            // f(x) ~ 1/(1+x^2)
            let cauchy = Cauchy::new(N::from(0.0), N::from(1.0)).unwrap();
            let mut result;

            loop {
                let mut comp_dev;

                loop {
                    // draw from the Cauchy distribution
                    comp_dev = rng.sample(cauchy);
                    // shift the peak of the comparison ditribution
                    result = self.sqrt_2lambda * comp_dev + self.lambda;
                    // repeat the drawing until we are in the range of possible values
                    if result >= N::from(0.0) {
                        break;
                    }
                }
                // now the result is a random variable greater than 0 with Cauchy distribution
                // the result should be an integer value
                result = result.floor();

                // this is the ratio of the Poisson distribution to the comparison distribution
                // the magic value scales the distribution function to a range of approximately 0-1
                // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
                // this doesn't change the resulting distribution, only increases the rate of failed drawings
                let check = N::from(0.9) * (N::from(1.0) + comp_dev * comp_dev)
                    * (result * self.log_lambda - log_gamma(N::from(1.0) + result) - self.magic_val).exp();

                // check with uniform random value - if below the threshold, we are within the target distribution
                if rng.gen::<N>() <= check {
                    break;
                }
            }
            result
        }
    }
}

impl<N: Float> Distribution<u64> for Poisson<N>
where Standard: Distribution<N>
{
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        let result: N = self.sample(rng);
        result.into_ui().unwrap()
    }
}

#[cfg(test)]
mod test {
    use crate::Distribution;
    use super::Poisson;

    #[test]
    fn test_poisson_10() {
        let poisson = Poisson::new(10.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum_u64 = 0;
        let mut sum_f64 = 0.;
        for _ in 0..1000 {
            let s_u64: u64 = poisson.sample(&mut rng);
            let s_f64: f64 = poisson.sample(&mut rng);
            sum_u64 += s_u64;
            sum_f64 += s_f64;
        }
        let avg_u64 = (sum_u64 as f64) / 1000.0;
        let avg_f64 = sum_f64 / 1000.0;
        println!("Poisson averages: {} (u64)  {} (f64)", avg_u64, avg_f64);
        for &avg in &[avg_u64, avg_f64] {
            assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
        }
    }

    #[test]
    fn test_poisson_15() {
        // Take the 'high expected values' path
        let poisson = Poisson::new(15.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum_u64 = 0;
        let mut sum_f64 = 0.;
        for _ in 0..1000 {
            let s_u64: u64 = poisson.sample(&mut rng);
            let s_f64: f64 = poisson.sample(&mut rng);
            sum_u64 += s_u64;
            sum_f64 += s_f64;
        }
        let avg_u64 = (sum_u64 as f64) / 1000.0;
        let avg_f64 = sum_f64 / 1000.0;
        println!("Poisson average: {} (u64)  {} (f64)", avg_u64, avg_f64);
        for &avg in &[avg_u64, avg_f64] {
            assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
        }
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_zero() {
        Poisson::new(0.0).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_neg() {
        Poisson::new(-10.0).unwrap();
    }
}
<commit_msg>rand_distr: Add tests for f32 sampling from Poisson<commit_after>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Poisson distribution.

use rand::Rng;
use crate::{Distribution, Cauchy, Standard};
use crate::utils::{log_gamma, Float};

/// The Poisson distribution `Poisson(lambda)`.
///
/// This distribution has a density function:
/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand_distr::{Poisson, Distribution};
///
/// let poi = Poisson::new(2.0).unwrap();
/// let v: u64 = poi.sample(&mut rand::thread_rng());
/// println!("{} is from a Poisson(2) distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Poisson<N> {
    lambda: N,
    // precalculated values
    exp_lambda: N,
    log_lambda: N,
    sqrt_2lambda: N,
    magic_val: N,
}

/// Error type returned from `Poisson::new`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
    /// `lambda <= 0` or `nan`.
    ShapeTooSmall,
}

impl<N: Float> Poisson<N> {
    /// Construct a new `Poisson` with the given shape parameter
    /// `lambda`.
    pub fn new(lambda: N) -> Result<Poisson<N>, Error> {
        if !(lambda > N::from(0.0)) {
            return Err(Error::ShapeTooSmall);
        }
        let log_lambda = lambda.ln();
        Ok(Poisson {
            lambda,
            exp_lambda: (-lambda).exp(),
            log_lambda,
            sqrt_2lambda: (N::from(2.0) * lambda).sqrt(),
            magic_val: lambda * log_lambda - log_gamma(N::from(1.0) + lambda),
        })
    }
}

impl<N: Float> Distribution<N> for Poisson<N>
where Standard: Distribution<N>
{
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N {
        // using the algorithm from Numerical Recipes in C

        // for low expected values use the Knuth method
        if self.lambda < N::from(12.0) {
            let mut result = N::from(0.);
            let mut p = N::from(1.0);
            while p > self.exp_lambda {
                p *= rng.gen::<N>();
                result += N::from(1.);
            }
            result - N::from(1.)
        }
        // high expected values - rejection method
        else {
            // we use the Cauchy distribution as the comparison distribution
            // f(x) ~ 1/(1+x^2)
            let cauchy = Cauchy::new(N::from(0.0), N::from(1.0)).unwrap();
            let mut result;

            loop {
                let mut comp_dev;

                loop {
                    // draw from the Cauchy distribution
                    comp_dev = rng.sample(cauchy);
                    // shift the peak of the comparison ditribution
                    result = self.sqrt_2lambda * comp_dev + self.lambda;
                    // repeat the drawing until we are in the range of possible values
                    if result >= N::from(0.0) {
                        break;
                    }
                }
                // now the result is a random variable greater than 0 with Cauchy distribution
                // the result should be an integer value
                result = result.floor();

                // this is the ratio of the Poisson distribution to the comparison distribution
                // the magic value scales the distribution function to a range of approximately 0-1
                // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
                // this doesn't change the resulting distribution, only increases the rate of failed drawings
                let check = N::from(0.9) * (N::from(1.0) + comp_dev * comp_dev)
                    * (result * self.log_lambda - log_gamma(N::from(1.0) + result) - self.magic_val).exp();

                // check with uniform random value - if below the threshold, we are within the target distribution
                if rng.gen::<N>() <= check {
                    break;
                }
            }
            result
        }
    }
}

impl<N: Float> Distribution<u64> for Poisson<N>
where Standard: Distribution<N>
{
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        let result: N = self.sample(rng);
        result.into_ui().unwrap()
    }
}

#[cfg(test)]
mod test {
    use crate::Distribution;
    use super::Poisson;

    #[test]
    fn test_poisson_10() {
        let poisson = Poisson::new(10.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum_u64 = 0;
        let mut sum_f64 = 0.;
        for _ in 0..1000 {
            let s_u64: u64 = poisson.sample(&mut rng);
            let s_f64: f64 = poisson.sample(&mut rng);
            sum_u64 += s_u64;
            sum_f64 += s_f64;
        }
        let avg_u64 = (sum_u64 as f64) / 1000.0;
        let avg_f64 = sum_f64 / 1000.0;
        println!("Poisson averages: {} (u64)  {} (f64)", avg_u64, avg_f64);
        for &avg in &[avg_u64, avg_f64] {
            assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
        }
    }

    #[test]
    fn test_poisson_15() {
        // Take the 'high expected values' path
        let poisson = Poisson::new(15.0).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum_u64 = 0;
        let mut sum_f64 = 0.;
        for _ in 0..1000 {
            let s_u64: u64 = poisson.sample(&mut rng);
            let s_f64: f64 = poisson.sample(&mut rng);
            sum_u64 += s_u64;
            sum_f64 += s_f64;
        }
        let avg_u64 = (sum_u64 as f64) / 1000.0;
        let avg_f64 = sum_f64 / 1000.0;
        println!("Poisson average: {} (u64)  {} (f64)", avg_u64, avg_f64);
        for &avg in &[avg_u64, avg_f64] {
            assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
        }
    }

    #[test]
    fn test_poisson_10_f32() {
        let poisson = Poisson::new(10.0f32).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum_u64 = 0;
        let mut sum_f32 = 0.;
        for _ in 0..1000 {
            let s_u64: u64 = poisson.sample(&mut rng);
            let s_f32: f32 = poisson.sample(&mut rng);
            sum_u64 += s_u64;
            sum_f32 += s_f32;
        }
        let avg_u64 = (sum_u64 as f32) / 1000.0;
        let avg_f32 = sum_f32 / 1000.0;
        println!("Poisson averages: {} (u64)  {} (f32)", avg_u64, avg_f32);
        for &avg in &[avg_u64, avg_f32] {
            assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
        }
    }

    #[test]
    fn test_poisson_15_f32() {
        // Take the 'high expected values' path
        let poisson = Poisson::new(15.0f32).unwrap();
        let mut rng = crate::test::rng(123);
        let mut sum_u64 = 0;
        let mut sum_f32 = 0.;
        for _ in 0..1000 {
            let s_u64: u64 = poisson.sample(&mut rng);
            let s_f32: f32 = poisson.sample(&mut rng);
            sum_u64 += s_u64;
            sum_f32 += s_f32;
        }
        let avg_u64 = (sum_u64 as f32) / 1000.0;
        let avg_f32 = sum_f32 / 1000.0;
        println!("Poisson average: {} (u64)  {} (f32)", avg_u64, avg_f32);
        for &avg in &[avg_u64, avg_f32] {
            assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
        }
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_zero() {
        Poisson::new(0.0).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_poisson_invalid_lambda_neg() {
        Poisson::new(-10.0).unwrap();
    }
}
<|endoftext|>