<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fs::OpenOptions;
use std::fmt;
use std::io;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::thread::sleep;
use std::time::Duration;
use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};

use libc;

use crate::gpio::{Level, Mode, PullUpDown, Error, Result};
use crate::system::DeviceInfo;

// The BCM2835 has 41 32-bit registers related to the GPIO (datasheet @ 6.1).
const GPIO_MEM_REGISTERS: usize = 41;
const GPIO_MEM_SIZE: usize = GPIO_MEM_REGISTERS * std::mem::size_of::<u32>();

const GPFSEL0:   usize = 0x00 / std::mem::size_of::<u32>();
const GPSET0:    usize = 0x1c / std::mem::size_of::<u32>();
const GPCLR0:    usize = 0x28 / std::mem::size_of::<u32>();
const GPLEV0:    usize = 0x34 / std::mem::size_of::<u32>();
const GPPUD:     usize = 0x94 / std::mem::size_of::<u32>();
const GPPUDCLK0: usize = 0x98 / std::mem::size_of::<u32>();

pub struct GpioMem {
    mem_ptr: *mut u32,
    locks: [AtomicBool; GPIO_MEM_REGISTERS],
}

impl fmt::Debug for GpioMem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("GpioMem")
            .field("mem_ptr", &self.mem_ptr)
            .field("locks", &format_args!("{{ .. }}"))
            .finish()
    }
}

impl GpioMem {
    pub fn open() -> Result<GpioMem> {
        // Try /dev/gpiomem first. If that fails, try /dev/mem instead. If neither works,
        // report back the error that's the most relevant.
        let mem_ptr = match Self::map_devgpiomem() {
            Ok(ptr) => ptr,
            Err(gpiomem_err) => match Self::map_devmem() {
                Ok(ptr) => ptr,
                Err(Error::Io(ref e)) if e.kind() == io::ErrorKind::PermissionDenied => {
                    return Err(Error::PermissionDenied)
                }
                Err(Error::UnknownSoC) => return Err(Error::UnknownSoC),
                _ => return Err(gpiomem_err),
            },
        };

        let locks = unsafe {
            let mut locks: [AtomicBool; GPIO_MEM_REGISTERS] = std::mem::uninitialized();

            for element in locks.iter_mut() {
                std::ptr::write(element, AtomicBool::new(false))
            }

            locks
        };

        Ok(GpioMem { mem_ptr, locks })
    }

    fn map_devgpiomem() -> Result<*mut u32> {
        // Open /dev/gpiomem with read/write/sync flags. This might fail if
        // /dev/gpiomem doesn't exist (< Raspbian Jessie), or /dev/gpiomem
        // doesn't have the appropriate permissions, or the current user is
        // not a member of the gpio group.
        let gpiomem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/gpiomem")?;

        // Memory-map /dev/gpiomem at offset 0
        let gpiomem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                gpiomem_file.as_raw_fd(),
                0,
            )
        };

        if gpiomem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(gpiomem_ptr as *mut u32)
    }

    fn map_devmem() -> Result<*mut u32> {
        // Identify which SoC we're using, so we know what offset to start at
        let device_info = DeviceInfo::new().map_err(|_| Error::UnknownSoC)?;

        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/mem")?;

        // Memory-map /dev/mem at the appropriate offset for our SoC
        let mem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                mem_file.as_raw_fd(),
                (device_info.peripheral_base() + device_info.gpio_offset()) as libc::off_t,
            )
        };

        if mem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(mem_ptr as *mut u32)
    }

    fn read(&self, offset: usize) -> u32 {
        loop {
          if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
            break;
          }
        }

        let reg_value = unsafe { ptr::read_volatile(self.mem_ptr.add(offset)) };

        self.locks[offset].store(false, Ordering::SeqCst);

        reg_value
    }

    fn write(&self, offset: usize, value: u32) {
        loop {
          if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
            break;
          }
        }

        unsafe {
            ptr::write_volatile(self.mem_ptr.add(offset), value);
        }

        self.locks[offset].store(false, Ordering::SeqCst);
    }

    pub fn set_high(&self, pin: u8) {
        let offset = GPSET0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn set_low(&self, pin: u8) {
        let offset = GPCLR0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn level(&self, pin: u8) -> Level {
        let offset = GPLEV0 + pin as usize / 32;
        let shift = pin % 32;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value & (1 << shift)) as u8) }
    }

    pub fn mode(&self, pin: u8) -> Mode {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value >> shift) as u8 & 0b111) }
    }

    pub fn set_mode(&self, pin: u8, mode: Mode) {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        loop {
          if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
            break;
          }
        }

        unsafe {
          let mem_ptr = self.mem_ptr.add(offset);
          let reg_value = ptr::read_volatile(mem_ptr);
          ptr::write_volatile(mem_ptr, (reg_value & !(0b111 << shift)) | ((mode as u32) << shift));
        }

        self.locks[offset].store(false, Ordering::SeqCst);
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    pub fn set_pullupdown(&self, pin: u8, pud: PullUpDown) {
        let offset = GPPUDCLK0 + pin as usize / 32;
        let shift = pin % 32;

        loop {
          if self.locks[GPPUD].compare_and_swap(false, true, Ordering::SeqCst) == false {
            if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
              break;
            } else {
              self.locks[GPPUD].store(false, Ordering::SeqCst);
            }
          }
        }

        // Set the control signal in GPPUD, while leaving the other 30
        // bits unchanged.
        let reg_value = self.read(GPPUD);
        self.write(GPPUD, (reg_value & !0b11) | ((pud as u32) & 0b11));

        // Set-up time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Clock the control signal into the selected pin.
        self.write(offset, 1 << shift);

        // Hold time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Remove the control signal and clock.
        let reg_value = self.read(GPPUD);
        self.write(GPPUD, reg_value & !0b11);
        self.write(offset, 0 << shift);

        self.locks[offset].store(false, Ordering::SeqCst);
        self.locks[GPPUD].store(false, Ordering::SeqCst);
    }
}

impl Drop for GpioMem {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.mem_ptr as *mut libc::c_void, GPIO_MEM_SIZE as libc::size_t);
        }
    }
}

// Required because of the raw pointer to our memory-mapped file
unsafe impl Send for GpioMem {}
unsafe impl Sync for GpioMem {}
<commit_msg>Fix deadlock.<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fs::OpenOptions;
use std::fmt;
use std::io;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::thread::sleep;
use std::time::Duration;
use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};

use libc;

use crate::gpio::{Level, Mode, PullUpDown, Error, Result};
use crate::system::DeviceInfo;

// The BCM2835 has 41 32-bit registers related to the GPIO (datasheet @ 6.1).
const GPIO_MEM_REGISTERS: usize = 41;
const GPIO_MEM_SIZE: usize = GPIO_MEM_REGISTERS * std::mem::size_of::<u32>();

const GPFSEL0:   usize = 0x00 / std::mem::size_of::<u32>();
const GPSET0:    usize = 0x1c / std::mem::size_of::<u32>();
const GPCLR0:    usize = 0x28 / std::mem::size_of::<u32>();
const GPLEV0:    usize = 0x34 / std::mem::size_of::<u32>();
const GPPUD:     usize = 0x94 / std::mem::size_of::<u32>();
const GPPUDCLK0: usize = 0x98 / std::mem::size_of::<u32>();

pub struct GpioMem {
    mem_ptr: *mut u32,
    locks: [AtomicBool; GPIO_MEM_REGISTERS],
}

impl fmt::Debug for GpioMem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("GpioMem")
            .field("mem_ptr", &self.mem_ptr)
            .field("locks", &format_args!("{{ .. }}"))
            .finish()
    }
}

impl GpioMem {
    pub fn open() -> Result<GpioMem> {
        // Try /dev/gpiomem first. If that fails, try /dev/mem instead. If neither works,
        // report back the error that's the most relevant.
        let mem_ptr = match Self::map_devgpiomem() {
            Ok(ptr) => ptr,
            Err(gpiomem_err) => match Self::map_devmem() {
                Ok(ptr) => ptr,
                Err(Error::Io(ref e)) if e.kind() == io::ErrorKind::PermissionDenied => {
                    return Err(Error::PermissionDenied)
                }
                Err(Error::UnknownSoC) => return Err(Error::UnknownSoC),
                _ => return Err(gpiomem_err),
            },
        };

        let locks = unsafe {
            let mut locks: [AtomicBool; GPIO_MEM_REGISTERS] = std::mem::uninitialized();

            for element in locks.iter_mut() {
                std::ptr::write(element, AtomicBool::new(false))
            }

            locks
        };

        Ok(GpioMem { mem_ptr, locks })
    }

    fn map_devgpiomem() -> Result<*mut u32> {
        // Open /dev/gpiomem with read/write/sync flags. This might fail if
        // /dev/gpiomem doesn't exist (< Raspbian Jessie), or /dev/gpiomem
        // doesn't have the appropriate permissions, or the current user is
        // not a member of the gpio group.
        let gpiomem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/gpiomem")?;

        // Memory-map /dev/gpiomem at offset 0
        let gpiomem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                gpiomem_file.as_raw_fd(),
                0,
            )
        };

        if gpiomem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(gpiomem_ptr as *mut u32)
    }

    fn map_devmem() -> Result<*mut u32> {
        // Identify which SoC we're using, so we know what offset to start at
        let device_info = DeviceInfo::new().map_err(|_| Error::UnknownSoC)?;

        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/mem")?;

        // Memory-map /dev/mem at the appropriate offset for our SoC
        let mem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                mem_file.as_raw_fd(),
                (device_info.peripheral_base() + device_info.gpio_offset()) as libc::off_t,
            )
        };

        if mem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(mem_ptr as *mut u32)
    }

    fn read(&self, offset: usize) -> u32 {
        loop {
          if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
            break;
          }
        }

        let reg_value = unsafe { ptr::read_volatile(self.mem_ptr.add(offset)) };

        self.locks[offset].store(false, Ordering::SeqCst);

        reg_value
    }

    fn write(&self, offset: usize, value: u32) {
        loop {
          if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
            break;
          }
        }

        unsafe {
            ptr::write_volatile(self.mem_ptr.add(offset), value);
        }

        self.locks[offset].store(false, Ordering::SeqCst);
    }

    pub fn set_high(&self, pin: u8) {
        let offset = GPSET0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn set_low(&self, pin: u8) {
        let offset = GPCLR0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn level(&self, pin: u8) -> Level {
        let offset = GPLEV0 + pin as usize / 32;
        let shift = pin % 32;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value & (1 << shift)) as u8) }
    }

    pub fn mode(&self, pin: u8) -> Mode {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value >> shift) as u8 & 0b111) }
    }

    pub fn set_mode(&self, pin: u8, mode: Mode) {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        loop {
          if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
            break;
          }
        }

        unsafe {
          let mem_ptr = self.mem_ptr.add(offset);
          let reg_value = ptr::read_volatile(mem_ptr);
          ptr::write_volatile(mem_ptr, (reg_value & !(0b111 << shift)) | ((mode as u32) << shift));
        }

        self.locks[offset].store(false, Ordering::SeqCst);
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    pub fn set_pullupdown(&self, pin: u8, pud: PullUpDown) {
        let offset = GPPUDCLK0 + pin as usize / 32;
        let shift = pin % 32;

        loop {
          if self.locks[GPPUD].compare_and_swap(false, true, Ordering::SeqCst) == false {
            if self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) == false {
              break;
            } else {
              self.locks[GPPUD].store(false, Ordering::SeqCst);
            }
          }
        }

        // Set the control signal in GPPUD, while leaving the other 30
        // bits unchanged.
        unsafe {
          let mem_ptr = self.mem_ptr.add(GPPUD);
          let reg_value = ptr::read_volatile(mem_ptr);
          ptr::write_volatile(mem_ptr, (reg_value & !0b11) | ((pud as u32) & 0b11));
        }

        // Set-up time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Clock the control signal into the selected pin.
        unsafe {
          let mem_ptr = self.mem_ptr.add(offset);
          ptr::write_volatile(mem_ptr, 1 << shift);
        }

        // Hold time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Remove the control signal and clock.
        unsafe {
          let mem_ptr = self.mem_ptr.add(GPPUD);
          let reg_value = ptr::read_volatile(mem_ptr);
          ptr::write_volatile(mem_ptr, reg_value & !0b11);
        }

        unsafe {
          let mem_ptr = self.mem_ptr.add(offset);
          ptr::write_volatile(mem_ptr, 0 << shift);
        }

        self.locks[offset].store(false, Ordering::SeqCst);
        self.locks[GPPUD].store(false, Ordering::SeqCst);
    }
}

impl Drop for GpioMem {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.mem_ptr as *mut libc::c_void, GPIO_MEM_SIZE as libc::size_t);
        }
    }
}

// Required because of the raw pointer to our memory-mapped file
unsafe impl Send for GpioMem {}
unsafe impl Sync for GpioMem {}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fmt;
use std::fs::OpenOptions;
use std::io;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::sleep;
use std::time::Duration;

use libc;

use crate::gpio::{Error, Level, Mode, PullUpDown, Result};
use crate::system::DeviceInfo;

// The BCM2835 has 41 32-bit registers related to the GPIO (datasheet @ 6.1).
const GPIO_MEM_REGISTERS: usize = 41;
const GPIO_MEM_SIZE: usize = GPIO_MEM_REGISTERS * std::mem::size_of::<u32>();

const GPFSEL0: usize = 0x00;
const GPSET0: usize = 0x1c / std::mem::size_of::<u32>();
const GPCLR0: usize = 0x28 / std::mem::size_of::<u32>();
const GPLEV0: usize = 0x34 / std::mem::size_of::<u32>();
const GPPUD: usize = 0x94 / std::mem::size_of::<u32>();
const GPPUDCLK0: usize = 0x98 / std::mem::size_of::<u32>();

pub struct GpioMem {
    mem_ptr: *mut u32,
    locks: [AtomicBool; GPIO_MEM_REGISTERS],
}

impl fmt::Debug for GpioMem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("GpioMem")
            .field("mem_ptr", &self.mem_ptr)
            .field("locks", &format_args!("{{ .. }}"))
            .finish()
    }
}

impl GpioMem {
    pub fn open() -> Result<GpioMem> {
        // Try /dev/gpiomem first. If that fails, try /dev/mem instead. If neither works,
        // report back the error that's the most relevant.
        let mem_ptr = match Self::map_devgpiomem() {
            Ok(ptr) => ptr,
            Err(gpiomem_err) => match Self::map_devmem() {
                Ok(ptr) => ptr,
                Err(Error::Io(ref e)) if e.kind() == io::ErrorKind::PermissionDenied => {
                    return Err(Error::PermissionDenied)
                }
                Err(Error::UnknownModel) => return Err(Error::UnknownModel),
                _ => return Err(gpiomem_err),
            },
        };

        let locks = init_array!(AtomicBool::new(false), GPIO_MEM_REGISTERS);

        Ok(GpioMem { mem_ptr, locks })
    }

    fn map_devgpiomem() -> Result<*mut u32> {
        // Open /dev/gpiomem with read/write/sync flags. This might fail if
        // /dev/gpiomem doesn't exist (< Raspbian Jessie), or /dev/gpiomem
        // doesn't have the appropriate permissions, or the current user is
        // not a member of the gpio group.
        let gpiomem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/gpiomem")?;

        // Memory-map /dev/gpiomem at offset 0
        let gpiomem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                gpiomem_file.as_raw_fd(),
                0,
            )
        };

        if gpiomem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(gpiomem_ptr as *mut u32)
    }

    fn map_devmem() -> Result<*mut u32> {
        // Identify which SoC we're using, so we know what offset to start at
        let device_info = DeviceInfo::new().map_err(|_| Error::UnknownModel)?;

        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/mem")?;

        // Memory-map /dev/mem at the appropriate offset for our SoC
        let mem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                mem_file.as_raw_fd(),
                (device_info.peripheral_base() + device_info.gpio_offset()) as libc::off_t,
            )
        };

        if mem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(mem_ptr as *mut u32)
    }

    fn read(&self, offset: usize) -> u32 {
        loop {
            if !self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) {
                break;
            }
        }

        let reg_value = unsafe { ptr::read_volatile(self.mem_ptr.add(offset)) };

        self.locks[offset].store(false, Ordering::SeqCst);

        reg_value
    }

    fn write(&self, offset: usize, value: u32) {
        loop {
            if !self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) {
                break;
            }
        }

        unsafe {
            ptr::write_volatile(self.mem_ptr.add(offset), value);
        }

        self.locks[offset].store(false, Ordering::SeqCst);
    }

    pub fn set_high(&self, pin: u8) {
        let offset = GPSET0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn set_low(&self, pin: u8) {
        let offset = GPCLR0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn level(&self, pin: u8) -> Level {
        let offset = GPLEV0 + pin as usize / 32;
        let shift = pin % 32;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value >> shift) as u8 & 0b1) }
    }

    pub fn mode(&self, pin: u8) -> Mode {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value >> shift) as u8 & 0b111) }
    }

    pub fn set_mode(&self, pin: u8, mode: Mode) {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        loop {
            if !self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) {
                break;
            }
        }

        unsafe {
            let mem_ptr = self.mem_ptr.add(offset);
            let reg_value = ptr::read_volatile(mem_ptr);
            ptr::write_volatile(
                mem_ptr,
                (reg_value & !(0b111 << shift)) | ((mode as u32) << shift),
            );
        }

        self.locks[offset].store(false, Ordering::SeqCst);
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    pub fn set_pullupdown(&self, pin: u8, pud: PullUpDown) {
        let offset = GPPUDCLK0 + pin as usize / 32;
        let shift = pin % 32;

        loop {
            if !self.locks[GPPUD].compare_and_swap(false, true, Ordering::SeqCst) {
                if !self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) {
                    break;
                } else {
                    self.locks[GPPUD].store(false, Ordering::SeqCst);
                }
            }
        }

        // Set the control signal in GPPUD, while leaving the other 30
        // bits unchanged.
        unsafe {
            let mem_ptr = self.mem_ptr.add(GPPUD);
            let reg_value = ptr::read_volatile(mem_ptr);
            ptr::write_volatile(mem_ptr, (reg_value & !0b11) | ((pud as u32) & 0b11));
        }

        // Set-up time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Clock the control signal into the selected pin.
        unsafe {
            let mem_ptr = self.mem_ptr.add(offset);
            ptr::write_volatile(mem_ptr, 1 << shift);
        }

        // Hold time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Remove the control signal and clock.
        unsafe {
            let mem_ptr = self.mem_ptr.add(GPPUD);
            let reg_value = ptr::read_volatile(mem_ptr);
            ptr::write_volatile(mem_ptr, reg_value & !0b11);
        }

        unsafe {
            let mem_ptr = self.mem_ptr.add(offset);
            ptr::write_volatile(mem_ptr, 0 << shift);
        }

        self.locks[offset].store(false, Ordering::SeqCst);
        self.locks[GPPUD].store(false, Ordering::SeqCst);
    }
}

impl Drop for GpioMem {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(
                self.mem_ptr as *mut libc::c_void,
                GPIO_MEM_SIZE as libc::size_t,
            );
        }
    }
}

// Required because of the raw pointer to our memory-mapped file
unsafe impl Send for GpioMem {}
unsafe impl Sync for GpioMem {}
<commit_msg>Remove lock for read() and write()<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fmt;
use std::fs::OpenOptions;
use std::io;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::sleep;
use std::time::Duration;

use libc;

use crate::gpio::{Error, Level, Mode, PullUpDown, Result};
use crate::system::DeviceInfo;

// The BCM2835 has 41 32-bit registers related to the GPIO (datasheet @ 6.1).
const GPIO_MEM_REGISTERS: usize = 41;
const GPIO_MEM_SIZE: usize = GPIO_MEM_REGISTERS * std::mem::size_of::<u32>();

const GPFSEL0: usize = 0x00;
const GPSET0: usize = 0x1c / std::mem::size_of::<u32>();
const GPCLR0: usize = 0x28 / std::mem::size_of::<u32>();
const GPLEV0: usize = 0x34 / std::mem::size_of::<u32>();
const GPPUD: usize = 0x94 / std::mem::size_of::<u32>();
const GPPUDCLK0: usize = 0x98 / std::mem::size_of::<u32>();

pub struct GpioMem {
    mem_ptr: *mut u32,
    locks: [AtomicBool; GPIO_MEM_REGISTERS],
}

impl fmt::Debug for GpioMem {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("GpioMem")
            .field("mem_ptr", &self.mem_ptr)
            .field("locks", &format_args!("{{ .. }}"))
            .finish()
    }
}

impl GpioMem {
    pub fn open() -> Result<GpioMem> {
        // Try /dev/gpiomem first. If that fails, try /dev/mem instead. If neither works,
        // report back the error that's the most relevant.
        let mem_ptr = match Self::map_devgpiomem() {
            Ok(ptr) => ptr,
            Err(gpiomem_err) => match Self::map_devmem() {
                Ok(ptr) => ptr,
                Err(Error::Io(ref e)) if e.kind() == io::ErrorKind::PermissionDenied => {
                    return Err(Error::PermissionDenied)
                }
                Err(Error::UnknownModel) => return Err(Error::UnknownModel),
                _ => return Err(gpiomem_err),
            },
        };

        let locks = init_array!(AtomicBool::new(false), GPIO_MEM_REGISTERS);

        Ok(GpioMem { mem_ptr, locks })
    }

    fn map_devgpiomem() -> Result<*mut u32> {
        // Open /dev/gpiomem with read/write/sync flags. This might fail if
        // /dev/gpiomem doesn't exist (< Raspbian Jessie), or /dev/gpiomem
        // doesn't have the appropriate permissions, or the current user is
        // not a member of the gpio group.
        let gpiomem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/gpiomem")?;

        // Memory-map /dev/gpiomem at offset 0
        let gpiomem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                gpiomem_file.as_raw_fd(),
                0,
            )
        };

        if gpiomem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(gpiomem_ptr as *mut u32)
    }

    fn map_devmem() -> Result<*mut u32> {
        // Identify which SoC we're using, so we know what offset to start at
        let device_info = DeviceInfo::new().map_err(|_| Error::UnknownModel)?;

        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_SYNC)
            .open("/dev/mem")?;

        // Memory-map /dev/mem at the appropriate offset for our SoC
        let mem_ptr = unsafe {
            libc::mmap(
                ptr::null_mut(),
                GPIO_MEM_SIZE,
                libc::PROT_READ | libc::PROT_WRITE,
                libc::MAP_SHARED,
                mem_file.as_raw_fd(),
                (device_info.peripheral_base() + device_info.gpio_offset()) as libc::off_t,
            )
        };

        if mem_ptr == libc::MAP_FAILED {
            return Err(Error::Io(io::Error::last_os_error()));
        }

        Ok(mem_ptr as *mut u32)
    }

    #[inline]
    fn read(&self, offset: usize) -> u32 {
        unsafe { ptr::read_volatile(self.mem_ptr.add(offset)) }
    }

    #[inline]
    fn write(&self, offset: usize, value: u32) {
        unsafe {
            ptr::write_volatile(self.mem_ptr.add(offset), value);
        }
    }

    pub fn set_high(&self, pin: u8) {
        let offset = GPSET0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn set_low(&self, pin: u8) {
        let offset = GPCLR0 + pin as usize / 32;
        let shift = pin % 32;
        self.write(offset, 1 << shift);
    }

    pub fn level(&self, pin: u8) -> Level {
        let offset = GPLEV0 + pin as usize / 32;
        let shift = pin % 32;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value >> shift) as u8 & 0b1) }
    }

    pub fn mode(&self, pin: u8) -> Mode {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        let reg_value = self.read(offset);

        unsafe { std::mem::transmute((reg_value >> shift) as u8 & 0b111) }
    }

    pub fn set_mode(&self, pin: u8, mode: Mode) {
        let offset = GPFSEL0 + pin as usize / 10;
        let shift = (pin % 10) * 3;

        loop {
            if !self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) {
                break;
            }
        }

        let reg_value = self.read(offset);
        self.write(
            offset,
            (reg_value & !(0b111 << shift)) | ((mode as u32) << shift),
        );

        self.locks[offset].store(false, Ordering::SeqCst);
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    pub fn set_pullupdown(&self, pin: u8, pud: PullUpDown) {
        let offset = GPPUDCLK0 + pin as usize / 32;
        let shift = pin % 32;

        loop {
            if !self.locks[GPPUD].compare_and_swap(false, true, Ordering::SeqCst) {
                if !self.locks[offset].compare_and_swap(false, true, Ordering::SeqCst) {
                    break;
                } else {
                    self.locks[GPPUD].store(false, Ordering::SeqCst);
                }
            }
        }

        // Set the control signal in GPPUD.
        let reg_value = self.read(GPPUD);
        self.write(GPPUD, (reg_value & !0b11) | ((pud as u32) & 0b11));

        // The datasheet mentions waiting at least 150 cycles for set-up
        // and hold, but doesn't state which clock is used. 20µs is
        // probably too long, but it works and seems acceptable for a
        // one-time configuration function.

        // Set-up time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Clock the control signal into the selected pin.
        self.write(offset, 1 << shift);

        // Hold time for the control signal.
        sleep(Duration::new(0, 20000)); // >= 20µs

        // Remove the control signal and clock.
        self.write(GPPUD, reg_value & !0b11);
        self.write(offset, 0);

        self.locks[offset].store(false, Ordering::SeqCst);
        self.locks[GPPUD].store(false, Ordering::SeqCst);
    }
}

impl Drop for GpioMem {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(
                self.mem_ptr as *mut libc::c_void,
                GPIO_MEM_SIZE as libc::size_t,
            );
        }
    }
}

// Required because of the raw pointer to our memory-mapped file
unsafe impl Send for GpioMem {}
unsafe impl Sync for GpioMem {}
<|endoftext|>


<commit_before>use crate::adc::AdcDriver;
use crate::buttons::ButtonDriver;
use crate::console::ConsoleDriver;
use crate::gpio::GpioDriver;
use crate::led::LedDriver;
use crate::result::OtherError;
use crate::result::TockError;
use crate::result::TockResult;
use crate::rng::RngDriver;
use crate::sensors::ninedof::NinedofDriver;
use crate::sensors::AmbientLightSensor;
use crate::sensors::HumiditySensor;
use crate::sensors::TemperatureSensor;
use crate::simple_ble::BleAdvertisingDriver;
use crate::simple_ble::BleScanningDriver;
use crate::temperature::TemperatureDriver;
use crate::timer::DriverContext;
use core::cell::Cell;

/// Struct containing all drivers constructible through retrieve_hardware()
pub struct Hardware {
    pub console_driver: ConsoleDriver,
    pub led_driver: LedDriver,
    pub timer_context: DriverContext,
    pub gpio_driver: GpioDriver,
    pub temperature_driver: TemperatureDriver,
    pub button_driver: ButtonDriver,
    pub adc_driver: AdcDriver,
    pub rng_driver: RngDriver,
    pub ble_advertising_driver: BleAdvertisingDriver,
    pub ble_scanning_driver: BleScanningDriver,
    pub ambient_light_sensor: AmbientLightSensor,
    pub temperature_sensor: TemperatureSensor,
    pub humidity_sensor: HumiditySensor,
    pub ninedof_driver: NinedofDriver,
}

/// Retrieve Hardware struct. Returns Hardware only once.
pub fn retrieve_hardware() -> TockResult<Hardware> {
    match unsafe { HARDWARE_SINGLETON.take() } {
        Some(hardware) => Ok(hardware),
        None => Err(TockError::Other(OtherError::DriverAlreadyTaken)),
    }
}

/// Retrieve [Hardware] struct without check whether it has already been taken
/// at a different point.
/// # Safety
/// This shall only used in special situations where drivers cannot be passed as arguments
/// as in the panic handler. Otherwise global mutable state (as shared buffers) may be exposed
/// in an unsafe manner.
pub unsafe fn retrieve_hardware_unsafe() -> Hardware {
    HARDWARE
}

#[allow(clippy::declare_interior_mutable_const)]
const HARDWARE: Hardware = Hardware {
    console_driver: ConsoleDriver {
        _unconstructible: (),
    },
    led_driver: LedDriver {
        _unconstructible: (),
    },
    timer_context: DriverContext {
        active_timer: Cell::new(None),
    },
    gpio_driver: GpioDriver {
        _unconstructible: (),
    },
    temperature_driver: TemperatureDriver {
        _unconstructible: (),
    },
    button_driver: ButtonDriver {
        _unconstructible: (),
    },
    adc_driver: AdcDriver {
        _unconstructible: (),
    },
    rng_driver: RngDriver {
        _unconstructible: (),
    },
    ble_advertising_driver: BleAdvertisingDriver {
        _unconstructible: (),
    },
    ble_scanning_driver: BleScanningDriver {
        _unconstructible: (),
    },
    ambient_light_sensor: AmbientLightSensor {
        _unconstructible: (),
    },
    temperature_sensor: TemperatureSensor {
        _unconstructible: (),
    },
    humidity_sensor: HumiditySensor {
        _unconstructible: (),
    },
    ninedof_driver: NinedofDriver {
        _unconstructible: (),
    },
};

static mut HARDWARE_SINGLETON: Option<Hardware> = Some(HARDWARE);

#[cfg(test)]
mod test {
    use crate::retrieve_hardware;
    #[test]
    pub fn can_be_retrieved_once() {
        reset_hardware_singleton();

        assert!(retrieve_hardware().is_ok());
        assert!(retrieve_hardware().is_err());
    }

    fn reset_hardware_singleton() {
        unsafe {
            super::HARDWARE_SINGLETON = Some(super::HARDWARE);
        };
    }
}
<commit_msg>Add non-exhaustive attribute to Hardware<commit_after>use crate::adc::AdcDriver;
use crate::buttons::ButtonDriver;
use crate::console::ConsoleDriver;
use crate::gpio::GpioDriver;
use crate::led::LedDriver;
use crate::result::OtherError;
use crate::result::TockError;
use crate::result::TockResult;
use crate::rng::RngDriver;
use crate::sensors::ninedof::NinedofDriver;
use crate::sensors::AmbientLightSensor;
use crate::sensors::HumiditySensor;
use crate::sensors::TemperatureSensor;
use crate::simple_ble::BleAdvertisingDriver;
use crate::simple_ble::BleScanningDriver;
use crate::temperature::TemperatureDriver;
use crate::timer::DriverContext;
use core::cell::Cell;

/// Struct containing all drivers constructible through retrieve_hardware()
#[non_exhaustive]
pub struct Hardware {
    pub console_driver: ConsoleDriver,
    pub led_driver: LedDriver,
    pub timer_context: DriverContext,
    pub gpio_driver: GpioDriver,
    pub temperature_driver: TemperatureDriver,
    pub button_driver: ButtonDriver,
    pub adc_driver: AdcDriver,
    pub rng_driver: RngDriver,
    pub ble_advertising_driver: BleAdvertisingDriver,
    pub ble_scanning_driver: BleScanningDriver,
    pub ambient_light_sensor: AmbientLightSensor,
    pub temperature_sensor: TemperatureSensor,
    pub humidity_sensor: HumiditySensor,
    pub ninedof_driver: NinedofDriver,
}

/// Retrieve Hardware struct. Returns Hardware only once.
pub fn retrieve_hardware() -> TockResult<Hardware> {
    match unsafe { HARDWARE_SINGLETON.take() } {
        Some(hardware) => Ok(hardware),
        None => Err(TockError::Other(OtherError::DriverAlreadyTaken)),
    }
}

/// Retrieve [Hardware] struct without check whether it has already been taken
/// at a different point.
/// # Safety
/// This shall only used in special situations where drivers cannot be passed as arguments
/// as in the panic handler. Otherwise global mutable state (as shared buffers) may be exposed
/// in an unsafe manner.
pub unsafe fn retrieve_hardware_unsafe() -> Hardware {
    HARDWARE
}

#[allow(clippy::declare_interior_mutable_const)]
const HARDWARE: Hardware = Hardware {
    console_driver: ConsoleDriver {
        _unconstructible: (),
    },
    led_driver: LedDriver {
        _unconstructible: (),
    },
    timer_context: DriverContext {
        active_timer: Cell::new(None),
    },
    gpio_driver: GpioDriver {
        _unconstructible: (),
    },
    temperature_driver: TemperatureDriver {
        _unconstructible: (),
    },
    button_driver: ButtonDriver {
        _unconstructible: (),
    },
    adc_driver: AdcDriver {
        _unconstructible: (),
    },
    rng_driver: RngDriver {
        _unconstructible: (),
    },
    ble_advertising_driver: BleAdvertisingDriver {
        _unconstructible: (),
    },
    ble_scanning_driver: BleScanningDriver {
        _unconstructible: (),
    },
    ambient_light_sensor: AmbientLightSensor {
        _unconstructible: (),
    },
    temperature_sensor: TemperatureSensor {
        _unconstructible: (),
    },
    humidity_sensor: HumiditySensor {
        _unconstructible: (),
    },
    ninedof_driver: NinedofDriver {
        _unconstructible: (),
    },
};

static mut HARDWARE_SINGLETON: Option<Hardware> = Some(HARDWARE);

#[cfg(test)]
mod test {
    use crate::retrieve_hardware;
    #[test]
    pub fn can_be_retrieved_once() {
        reset_hardware_singleton();

        assert!(retrieve_hardware().is_ok());
        assert!(retrieve_hardware().is_err());
    }

    fn reset_hardware_singleton() {
        unsafe {
            super::HARDWARE_SINGLETON = Some(super::HARDWARE);
        };
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook 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, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon 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 ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use escape::escape_html;
use token::Token;
use book::{Book, Number};
use error::{Error,Result};

use mustache;

/// Renderer for HTML
///
/// Also used by Epub.
pub struct HtmlRenderer<'a> {
    book: &'a Book,

    pub footnotes: Vec<(String, String)>,
    pub current_chapter: [i32;6],
    pub current_numbering: bool,
    pub current_hide: bool,
    table_head: bool,
    footnote_number: u32,

    epub3: bool,
    verbatim: bool,
}

impl<'a> HtmlRenderer<'a> {
    /// Creates a new HTML renderer
    pub fn new(book: &'a Book) -> HtmlRenderer<'a> {
        HtmlRenderer {
            book: book,
            current_chapter: [0, 0, 0, 0, 0, 0],
            current_numbering: book.get_bool("numbering").unwrap(),
            current_hide: false,
            table_head: false,
            footnote_number: 0,
            footnotes: vec!(),
            epub3: false,
            verbatim: false
        }
    }

    /// Increase a header
    pub fn inc_header(&mut self, n: i32) {
        let n = n as usize;
        assert!(n < self.current_chapter.len());
        self.current_chapter[n] += 1;
        for i in n+1..self.current_chapter.len() {
            self.current_chapter[i] = 0;
        }
    }

    /// Returns a "x.y.z"
    pub fn get_numbers(&self) -> String {
        let mut output = String::new();
        for i in 0..self.current_chapter.len() {
            if self.current_chapter[i] == 0 {
                if i == self.current_chapter.len() - 1 {
                    break;
                }
                let bools:Vec<_> = self.current_chapter[i+1..].iter().map(|x| *x != 0).collect();
                if !bools.contains(&true) {
                    break;
                }
            }
            output.push_str(&format!("{}.", self.current_chapter[i])); //todo
        }
        output
    }

    /// Render books as a standalone HTML file
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::new();

        for &(n, ref v) in &self.book.chapters {
            self.current_hide = false;
            let book_numbering = self.book.get_bool("numbering").unwrap();
            match n {
                Number::Unnumbered => self.current_numbering = false,
                Number::Default => self.current_numbering = book_numbering,
                Number::Specified(n) => {
                    self.current_numbering = book_numbering;
                    self.current_chapter[0] = n - 1;
                },
                Number::Hidden => {
                    self.current_numbering = false;
                    self.current_hide = true;
                },
            }
            content.push_str(&self.render_html(v));
        }

        let template = mustache::compile_str(try!(self.book.get_template("html.template")).as_ref());
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .insert_str("style",
                        &try!(self.book.get_template("html.css")))
            .build();

        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// display side notes if option is to true
    pub fn render_side_notes(&mut self, res: &mut String) {
        if self.book.get_bool("side_notes").unwrap() {
            for (note_number, footnote) in self.footnotes.drain(..) {
                res.push_str(&format!("
\n{} {}\n
\n", note_number, footnote));
            }
        }
    }

    // display end notes, if side_notes option is set to false
    pub fn render_end_notes(&mut self, res: &mut String) {
        if !self.footnotes.is_empty() {
            res.push_str("
Notes
");
            res.push_str("
");
            for (note_number, footnote) in self.footnotes.drain(..) {
                res.push_str(&format!("
{}	{}
\n", note_number, footnote));
            }
            res.push_str("
");
        }
    }

    ///
    pub fn render_html(&mut self, tokens: &[Token])-> String {
        let mut res = String::new();
        for token in tokens {
            res.push_str(&self.parse_token(&token));
            self.render_side_notes(&mut res);
        }
        self.render_end_notes(&mut res);
        res
    }

    /// Transform a vector of `Token`s to HTML format.
    pub fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token));
        }
        res
    }

    /// Parse a single token.
    pub fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => if self.verbatim {
                escape_html(text)
            } else {
                escape_html(&self.book.clean(text.clone()))
            },
            Token::Paragraph(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Header(n, ref vec) => {
                self.inc_header(n - 1);
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering {
                    let chapter = self.current_chapter[0];
                    self.book.get_header(chapter, &self.render_vec(vec)).unwrap()
                } else {
                    format!("{} {}", self.get_numbers(), self.render_vec(vec))
                };
                format!("<h{}>{}</h{}>\n", n, self.book.clean(s), n)
            },
            Token::Emphasis(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Strong(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Code(ref vec) => format!("{}", self.render_vec(vec)),
            Token::BlockQuote(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::CodeBlock(ref language, ref vec) => {
                self.verbatim = true;
                let s = self.render_vec(vec);
                let output = if language.is_empty() {
                    format!("
{}
\n", s)
                } else {
                    format!("
{}
\n", language, s)
                };
                self.verbatim = false;
                output
            },
            Token::Rule => String::from("
***
\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("
\n"),
            Token::List(ref vec) => format!("
\n{}
\n", self.render_vec(vec)),
            Token::OrderedList(n, ref vec) => format!("
\n{}
\n",
                                                      if n != 1 {
                                                          format!(" start = \"{}\"", n)
                                                      } else {
                                                          String::new()
                                                      },
                                                      self.render_vec(vec)),
            Token::Item(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Link(ref url, ref title, ref vec) => format!("{}",
                                                                url,
                                                                if title.is_empty() {
                                                                    String::new()
                                                                } else {
                                                                    format!(" title = \"{}\"", title)
                                                                },
                                                                self.render_vec(vec)),
            Token::Image(ref url, ref title, ref alt) => format!("",
                                                                 url,
                                                                 title,
                                                                 self.render_vec(alt)),
            Token::Table(_, ref vec) => format!("

\n{}

\n", self.render_vec(vec)),
            Token::TableRow(ref vec) => format!("
\n{}
\n", self.render_vec(vec)),
            Token::TableCell(ref vec) => {
                let tag = if self.table_head {"th"} else {"td"};
                format!("<{}>{}</{}>", tag, self.render_vec(vec), tag)
            },
            Token::TableHead(ref vec) => {
                self.table_head = true;
                let s = self.render_vec(vec);
                self.table_head = false;
                format!("
\n{}
\n", s)
            },
            Token::Footnote(ref vec) => {
                self.footnote_number += 1;
                let number = self.footnote_number;
                assert!(!vec.is_empty());

                let note_number = format!("

  [{}]

", number, number);

                let inner = format!("{}",
                                    if self.epub3 {r#"epub:type="footnote"#}else{""},
                                    number, self.render_vec(vec));
                self.footnotes.push((note_number, inner));

                format!("{}",
                        if self.epub3 {"epub:type = \"noteref\""} else {""},
                        number, number, number)
            },
        }
    }
}

<commit_msg>html: correctly turs off numbering<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook 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, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon 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 ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use escape::escape_html;
use token::Token;
use book::{Book, Number};
use error::{Error,Result};

use mustache;

/// Renderer for HTML
///
/// Also used by Epub.
pub struct HtmlRenderer<'a> {
    book: &'a Book,

    pub footnotes: Vec<(String, String)>,
    pub current_chapter: [i32;6],
    pub current_numbering: bool,
    pub current_hide: bool,
    table_head: bool,
    footnote_number: u32,

    epub3: bool,
    verbatim: bool,
}

impl<'a> HtmlRenderer<'a> {
    /// Creates a new HTML renderer
    pub fn new(book: &'a Book) -> HtmlRenderer<'a> {
        HtmlRenderer {
            book: book,
            current_chapter: [0, 0, 0, 0, 0, 0],
            current_numbering: book.get_bool("numbering").unwrap(),
            current_hide: false,
            table_head: false,
            footnote_number: 0,
            footnotes: vec!(),
            epub3: false,
            verbatim: false
        }
    }

    /// Increase a header
    pub fn inc_header(&mut self, n: i32) {
        let n = n as usize;
        assert!(n < self.current_chapter.len());
        self.current_chapter[n] += 1;
        for i in n+1..self.current_chapter.len() {
            self.current_chapter[i] = 0;
        }
    }

    /// Returns a "x.y.z"
    pub fn get_numbers(&self) -> String {
        let mut output = String::new();
        for i in 0..self.current_chapter.len() {
            if self.current_chapter[i] == 0 {
                if i == self.current_chapter.len() - 1 {
                    break;
                }
                let bools:Vec<_> = self.current_chapter[i+1..].iter().map(|x| *x != 0).collect();
                if !bools.contains(&true) {
                    break;
                }
            }
            output.push_str(&format!("{}.", self.current_chapter[i])); //todo
        }
        output
    }

    /// Render books as a standalone HTML file
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::new();

        for &(n, ref v) in &self.book.chapters {
            self.current_hide = false;
            let book_numbering = self.book.get_bool("numbering").unwrap();
            match n {
                Number::Unnumbered => self.current_numbering = false,
                Number::Default => self.current_numbering = book_numbering,
                Number::Specified(n) => {
                    self.current_numbering = book_numbering;
                    self.current_chapter[0] = n - 1;
                },
                Number::Hidden => {
                    self.current_numbering = false;
                    self.current_hide = true;
                },
            }
            content.push_str(&self.render_html(v));
        }

        let template = mustache::compile_str(try!(self.book.get_template("html.template")).as_ref());
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .insert_str("style",
                        &try!(self.book.get_template("html.css")))
            .build();

        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// display side notes if option is to true
    pub fn render_side_notes(&mut self, res: &mut String) {
        if self.book.get_bool("side_notes").unwrap() {
            for (note_number, footnote) in self.footnotes.drain(..) {
                res.push_str(&format!("
\n{} {}\n
\n", note_number, footnote));
            }
        }
    }

    // display end notes, if side_notes option is set to false
    pub fn render_end_notes(&mut self, res: &mut String) {
        if !self.footnotes.is_empty() {
            res.push_str("
Notes
");
            res.push_str("
");
            for (note_number, footnote) in self.footnotes.drain(..) {
                res.push_str(&format!("
{}	{}
\n", note_number, footnote));
            }
            res.push_str("
");
        }
    }

    ///
    pub fn render_html(&mut self, tokens: &[Token])-> String {
        let mut res = String::new();
        for token in tokens {
            res.push_str(&self.parse_token(&token));
            self.render_side_notes(&mut res);
        }
        self.render_end_notes(&mut res);
        res
    }

    /// Transform a vector of `Token`s to HTML format.
    pub fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(&token));
        }
        res
    }

    /// Parse a single token.
    pub fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => if self.verbatim {
                escape_html(text)
            } else {
                escape_html(&self.book.clean(text.clone()))
            },
            Token::Paragraph(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Header(n, ref vec) => {
                self.inc_header(n - 1);
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering {
                    let chapter = self.current_chapter[0];
                    self.book.get_header(chapter, &self.render_vec(vec)).unwrap()
                } else if self.current_numbering {
                    format!("{} {}", self.get_numbers(), self.render_vec(vec))
                } else {
                    self.render_vec(vec)
                };
                format!("<h{}>{}</h{}>\n", n, s, n)
            },
            Token::Emphasis(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Strong(ref vec) => format!("{}", self.render_vec(vec)),
            Token::Code(ref vec) => format!("{}", self.render_vec(vec)),
            Token::BlockQuote(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::CodeBlock(ref language, ref vec) => {
                self.verbatim = true;
                let s = self.render_vec(vec);
                let output = if language.is_empty() {
                    format!("
{}
\n", s)
                } else {
                    format!("
{}
\n", language, s)
                };
                self.verbatim = false;
                output
            },
            Token::Rule => String::from("
***
\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("
\n"),
            Token::List(ref vec) => format!("
\n{}
\n", self.render_vec(vec)),
            Token::OrderedList(n, ref vec) => format!("
\n{}
\n",
                                                      if n != 1 {
                                                          format!(" start = \"{}\"", n)
                                                      } else {
                                                          String::new()
                                                      },
                                                      self.render_vec(vec)),
            Token::Item(ref vec) => format!("
{}
\n", self.render_vec(vec)),
            Token::Link(ref url, ref title, ref vec) => format!("{}",
                                                                url,
                                                                if title.is_empty() {
                                                                    String::new()
                                                                } else {
                                                                    format!(" title = \"{}\"", title)
                                                                },
                                                                self.render_vec(vec)),
            Token::Image(ref url, ref title, ref alt) => format!("",
                                                                 url,
                                                                 title,
                                                                 self.render_vec(alt)),
            Token::Table(_, ref vec) => format!("

\n{}

\n", self.render_vec(vec)),
            Token::TableRow(ref vec) => format!("
\n{}
\n", self.render_vec(vec)),
            Token::TableCell(ref vec) => {
                let tag = if self.table_head {"th"} else {"td"};
                format!("<{}>{}</{}>", tag, self.render_vec(vec), tag)
            },
            Token::TableHead(ref vec) => {
                self.table_head = true;
                let s = self.render_vec(vec);
                self.table_head = false;
                format!("
\n{}
\n", s)
            },
            Token::Footnote(ref vec) => {
                self.footnote_number += 1;
                let number = self.footnote_number;
                assert!(!vec.is_empty());

                let note_number = format!("

  [{}]

", number, number);

                let inner = format!("{}",
                                    if self.epub3 {r#"epub:type="footnote"#}else{""},
                                    number, self.render_vec(vec));
                self.footnotes.push((note_number, inner));

                format!("{}",
                        if self.epub3 {"epub:type = \"noteref\""} else {""},
                        number, number, number)
            },
        }
    }
}

<|endoftext|>


<commit_before>pub fn remove_to<'s>(s: &'s str, c: char) -> &'s str {
    match s.rfind(c) {
        Some(pos) => &s[(pos + 1)..],
        None => s
    }
}

pub fn remove_suffix<'s>(s: &'s str, suffix: &str) -> &'s str {
    if !s.ends_with(suffix) {
        panic!();
    }
    &s[..(s.len() - suffix.len())]
}

#[cfg(test)]
mod test {

    use super::remove_to;
    use super::remove_suffix;

    #[test]
    fn test_remove_to() {
        assert_eq!("aaa", remove_to("aaa", '.'));
        assert_eq!("bbb", remove_to("aaa.bbb", '.'));
        assert_eq!("ccc", remove_to("aaa.bbb.ccc", '.'));
    }

    #[test]
    #[should_panic]
    fn test_remove_prefix_fail() {
        remove_prefix("aaa", "bbb");
    }

    #[test]
    fn test_remove_suffix() {
        assert_eq!("bbb", remove_suffix("bbbaaa", "aaa"));
    }

    #[test]
    #[should_panic]
    fn test_remove_suffix_fail() {
        remove_suffix("aaa", "bbb");
    }
}
<commit_msg>fix test compilation<commit_after>pub fn remove_to<'s>(s: &'s str, c: char) -> &'s str {
    match s.rfind(c) {
        Some(pos) => &s[(pos + 1)..],
        None => s
    }
}

pub fn remove_suffix<'s>(s: &'s str, suffix: &str) -> &'s str {
    if !s.ends_with(suffix) {
        panic!();
    }
    &s[..(s.len() - suffix.len())]
}

#[cfg(test)]
mod test {

    use super::remove_to;
    use super::remove_suffix;

    #[test]
    fn test_remove_to() {
        assert_eq!("aaa", remove_to("aaa", '.'));
        assert_eq!("bbb", remove_to("aaa.bbb", '.'));
        assert_eq!("ccc", remove_to("aaa.bbb.ccc", '.'));
    }

    #[test]
    fn test_remove_suffix() {
        assert_eq!("bbb", remove_suffix("bbbaaa", "aaa"));
    }

    #[test]
    #[should_panic]
    fn test_remove_suffix_fail() {
        remove_suffix("aaa", "bbb");
    }
}
<|endoftext|>


<commit_before>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! A module for dealing with decoupled lifetime and ownership.
//!
//! A lifeline and owner come in pairs: the lifeline is in control of the
//! lifetime of the stored value, but the owner is only one who can access the
//! value. If the lifeline is dropped, the stored value is dropped as well. The
//! owner will not be able to use the value then. If the owner consumes the
//! value, dropping the lifeline is a no-op.

use std::cell::RefCell;
use std::rc::{Rc, Weak};

/// Struct that controls the lifetime of the value in the lifeline-owner pair.
pub struct Lifeline<T> {
    #[allow(dead_code)] // This code is not dead, the Rc keeps the value alive.
    value: Rc<RefCell<Option<T>>>,
}

/// Struct that allows access to the value in the lifeline-owner pair.
pub struct Owner<T> {
    value: Weak<RefCell<Option<T>>>,
}

impl<T> Owner<T> {
    /// Performs the action on the stored value if it is still alive.
    pub fn with_value<F: FnOnce(&T)>(&self, action: F) {
        if let Some(cell) = self.value.upgrade() {
            if let Some(ref value) = *cell.borrow() {
                action(value);
            }
        }
    }

    /// Performs the action on the stored value if it is still alive.
    pub fn with_mut_value<F: FnOnce(&mut T)>(&mut self, action: F) {
        if let Some(cell) = self.value.upgrade() {
            if let Some(ref mut value) = *cell.borrow_mut() {
                action(value);
            }
        }
    }

    /// Returns the stored value if it is still alive.
    pub fn take(self) -> Option<T> {
        if let Some(cell) = self.value.upgrade() {
            cell.borrow_mut().take()
        } else {
            None
        }
    }
}

/// Creates a value with decoupled lifetime and ownership.
pub fn new<T>(value: T) -> (Lifeline<T>, Owner<T>) {
    let rc = Rc::new(RefCell::new(Some(value)));
    let owner = Owner { value: Rc::downgrade(&rc) };
    let lifeline = Lifeline { value: rc };
    (lifeline, owner)
}
<commit_msg>Remove unused method<commit_after>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! A module for dealing with decoupled lifetime and ownership.
//!
//! A lifeline and owner come in pairs: the lifeline is in control of the
//! lifetime of the stored value, but the owner is only one who can access the
//! value. If the lifeline is dropped, the stored value is dropped as well. The
//! owner will not be able to use the value then. If the owner consumes the
//! value, dropping the lifeline is a no-op.

use std::cell::RefCell;
use std::rc::{Rc, Weak};

/// Struct that controls the lifetime of the value in the lifeline-owner pair.
pub struct Lifeline<T> {
    #[allow(dead_code)] // This code is not dead, the Rc keeps the value alive.
    value: Rc<RefCell<Option<T>>>,
}

/// Struct that allows access to the value in the lifeline-owner pair.
pub struct Owner<T> {
    value: Weak<RefCell<Option<T>>>,
}

impl<T> Owner<T> {
    /// Performs the action on the stored value if it is still alive.
    pub fn with_mut_value<F: FnOnce(&mut T)>(&mut self, action: F) {
        if let Some(cell) = self.value.upgrade() {
            if let Some(ref mut value) = *cell.borrow_mut() {
                action(value);
            }
        }
    }

    /// Returns the stored value if it is still alive.
    pub fn take(self) -> Option<T> {
        if let Some(cell) = self.value.upgrade() {
            cell.borrow_mut().take()
        } else {
            None
        }
    }
}

/// Creates a value with decoupled lifetime and ownership.
pub fn new<T>(value: T) -> (Lifeline<T>, Owner<T>) {
    let rc = Rc::new(RefCell::new(Some(value)));
    let owner = Owner { value: Rc::downgrade(&rc) };
    let lifeline = Lifeline { value: rc };
    (lifeline, owner)
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::{env, str};
use std::error::Error;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use toml;

use dependency::Dependency;

/// Enumeration of errors which can occur when working with a rust manifest.
quick_error! {
    #[derive(Debug)]
    pub enum ManifestError {
        /// Cargo.toml could not be found.
        MissingManifest {
            description("missing manifest")
            display("Your Cargo.toml is missing.")
        }
        /// The TOML table could not be found.
        NonExistentTable(table: String) {
            description("non existent table")
            display("The table `{}` could not be found.", table)
        }
        /// The dependency could not be found.
        NonExistentDependency(name: String, table: String) {
            description("non existent dependency")
            display("The dependency `{}` could not be found in `{}`.", name, table)
        }
    }
}

enum CargoFile {
    Config,
    Lock,
}

/// A Cargo Manifest
#[derive(Debug, Clone, PartialEq)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml::Table,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<&str>, file: CargoFile) -> Result<PathBuf, Box<Error>> {
    let file_path = specified.map(PathBuf::from);

    if let Some(path) = file_path {
        if try!(fs::metadata(&path)).is_file() {
            Ok(path)
        } else {
            search(&path, file).map_err(From::from)
        }
    } else {
        env::current_dir()
            .map_err(From::from)
            .and_then(|ref dir| search(dir, file).map_err(From::from))
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path, file: CargoFile) -> Result<PathBuf, ManifestError> {
    let manifest = match file {
        CargoFile::Config => dir.join("Cargo.toml"),
        CargoFile::Lock => dir.join("Cargo.lock"),
    };

    fs::metadata(&manifest)
        .map(|_| manifest)
        .or(dir.parent().ok_or(ManifestError::MissingManifest).and_then(|dir| search(dir, file)))
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Config).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Look for a `Cargo.lock` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process' working directory is used as a starting point.
    pub fn find_lock_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Lock).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Open the `Cargo.lock` for a path (or the process' `cwd`)
    pub fn open_lock_file(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_lock_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file(&self, file: &mut File) -> Result<(), Box<Error>> {
        let mut toml = self.data.clone();

        let (proj_header, proj_data) = try!(toml.remove("package")
                                                .map(|data| ("package", data))
                                                .or_else(|| {
                                                    toml.remove("project")
                                                        .map(|data| ("project", data))
                                                })
                                                .ok_or(ManifestError::MissingManifest));

        let new_contents = format!("[{}]\n{}{}",
                                   proj_header,
                                   proj_data,
                                   toml::Value::Table(toml));
        let new_contents_bytes = new_contents.as_bytes();

        // We need to truncate the file, otherwise the new contents
        // will be mixed up with the old ones.
        try!(file.set_len(new_contents_bytes.len() as u64));
        file.write_all(new_contents_bytes).map_err(From::from)
    }

    /// Add entry to a Cargo.toml.
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn insert_into_table(&mut self,
                             table: &str,
                             dep: &Dependency)
                             -> Result<(), ManifestError> {
        let (ref name, ref data) = dep.to_toml();
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table))
                            .or_insert(toml::Value::Table(BTreeMap::new()));
        match *entry {
            toml::Value::Table(ref mut deps) => {
                deps.insert(name.clone(), data.clone());
                Ok(())
            }
            _ => Err(ManifestError::NonExistentTable(table.into())),
        }
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml;
    /// # fn main() {
    ///     use cargo_edit::{Dependency, Manifest};
    ///     use toml;
    ///
    ///     let mut manifest = Manifest { data: toml::Table::new() };
    ///     let dep = Dependency::new("cargo-edit").set_version("0.1.0");
    ///     let _ = manifest.insert_into_table("dependencies", &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    /// # }
    /// ```
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table));

        match entry {
            Entry::Vacant(_) => Err(ManifestError::NonExistentTable(table.into())),
            Entry::Occupied(entry) => {
                match *entry.into_mut() {
                    toml::Value::Table(ref mut deps) => {
                        deps.remove(name)
                            .map(|_| ())
                            .ok_or(ManifestError::NonExistentDependency(name.into(), table.into()))
                    }
                    _ => Err(ManifestError::NonExistentTable(table.into())),
                }
            }
        }
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &str, deps: &[Dependency]) -> Result<(), Box<Error>> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, &dep))
            .collect::<Result<Vec<_>, _>>()
            .map_err(From::from)
            .map(|_| ())
    }
}

impl str::FromStr for Manifest {
    type Err = Box<Error>;

    /// Read manifest data from string
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = toml::Parser::new(&input);

        parser.parse()
              .ok_or(parser.errors.pop())
              .map_err(Option::unwrap)
              .map_err(From::from)
              .map(|data| Manifest { data: data })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use dependency::Dependency;
    use toml;

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let copy = manifest.clone();
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
        assert_eq!(manifest, copy);
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let other_dep = Dependency::new("other-dep").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &other_dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }
}
<commit_msg>Remove manifest section after last dep removed<commit_after>use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::{env, str};
use std::error::Error;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use toml;

use dependency::Dependency;

/// Enumeration of errors which can occur when working with a rust manifest.
quick_error! {
    #[derive(Debug)]
    pub enum ManifestError {
        /// Cargo.toml could not be found.
        MissingManifest {
            description("missing manifest")
            display("Your Cargo.toml is missing.")
        }
        /// The TOML table could not be found.
        NonExistentTable(table: String) {
            description("non existent table")
            display("The table `{}` could not be found.", table)
        }
        /// The dependency could not be found.
        NonExistentDependency(name: String, table: String) {
            description("non existent dependency")
            display("The dependency `{}` could not be found in `{}`.", name, table)
        }
    }
}

enum CargoFile {
    Config,
    Lock,
}

/// A Cargo Manifest
#[derive(Debug, Clone, PartialEq)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml::Table,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<&str>, file: CargoFile) -> Result<PathBuf, Box<Error>> {
    let file_path = specified.map(PathBuf::from);

    if let Some(path) = file_path {
        if try!(fs::metadata(&path)).is_file() {
            Ok(path)
        } else {
            search(&path, file).map_err(From::from)
        }
    } else {
        env::current_dir()
            .map_err(From::from)
            .and_then(|ref dir| search(dir, file).map_err(From::from))
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path, file: CargoFile) -> Result<PathBuf, ManifestError> {
    let manifest = match file {
        CargoFile::Config => dir.join("Cargo.toml"),
        CargoFile::Lock => dir.join("Cargo.lock"),
    };

    fs::metadata(&manifest)
        .map(|_| manifest)
        .or(dir.parent().ok_or(ManifestError::MissingManifest).and_then(|dir| search(dir, file)))
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Config).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Look for a `Cargo.lock` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process' working directory is used as a starting point.
    pub fn find_lock_file(path: &Option<&str>) -> Result<File, Box<Error>> {
        find(path, CargoFile::Lock).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .map_err(From::from)
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Open the `Cargo.lock` for a path (or the process' `cwd`)
    pub fn open_lock_file(path: &Option<&str>) -> Result<Manifest, Box<Error>> {
        let mut file = try!(Manifest::find_lock_file(path));
        let mut data = String::new();
        try!(file.read_to_string(&mut data));

        data.parse()
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file(&self, file: &mut File) -> Result<(), Box<Error>> {
        let mut toml = self.data.clone();

        let (proj_header, proj_data) = try!(toml.remove("package")
                                                .map(|data| ("package", data))
                                                .or_else(|| {
                                                    toml.remove("project")
                                                        .map(|data| ("project", data))
                                                })
                                                .ok_or(ManifestError::MissingManifest));

        let new_contents = format!("[{}]\n{}{}",
                                   proj_header,
                                   proj_data,
                                   toml::Value::Table(toml));
        let new_contents_bytes = new_contents.as_bytes();

        // We need to truncate the file, otherwise the new contents
        // will be mixed up with the old ones.
        try!(file.set_len(new_contents_bytes.len() as u64));
        file.write_all(new_contents_bytes).map_err(From::from)
    }

    /// Add entry to a Cargo.toml.
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn insert_into_table(&mut self,
                             table: &str,
                             dep: &Dependency)
                             -> Result<(), ManifestError> {
        let (ref name, ref data) = dep.to_toml();
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table))
                            .or_insert(toml::Value::Table(BTreeMap::new()));
        match *entry {
            toml::Value::Table(ref mut deps) => {
                deps.insert(name.clone(), data.clone());
                Ok(())
            }
            _ => Err(ManifestError::NonExistentTable(table.into())),
        }
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml;
    /// # fn main() {
    ///     use cargo_edit::{Dependency, Manifest};
    ///     use toml;
    ///
    ///     let mut manifest = Manifest { data: toml::Table::new() };
    ///     let dep = Dependency::new("cargo-edit").set_version("0.1.0");
    ///     let _ = manifest.insert_into_table("dependencies", &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    /// # }
    /// ```
    #[cfg_attr(feature = "dev", allow(toplevel_ref_arg))]
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<(), ManifestError> {
        let ref mut manifest = self.data;
        let entry = manifest.entry(String::from(table));

        match entry {
            Entry::Vacant(_) => Err(ManifestError::NonExistentTable(table.into())),
            Entry::Occupied(mut entry) => {
                let result = match *entry.get_mut() {
                    toml::Value::Table(ref mut deps) => {
                        deps.remove(name)
                            .map(|_| ())
                            .ok_or(ManifestError::NonExistentDependency(name.into(), table.into()))
                    }
                    _ => Err(ManifestError::NonExistentTable(table.into())),
                };
                if let Some(b) = entry.get().as_table().and_then(|x| Some(x.is_empty())) {
                    if b {
                        entry.remove();
                    }
                }
                result
            }
        }
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &str, deps: &[Dependency]) -> Result<(), Box<Error>> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, &dep))
            .collect::<Result<Vec<_>, _>>()
            .map_err(From::from)
            .map(|_| ())
    }
}

impl str::FromStr for Manifest {
    type Err = Box<Error>;

    /// Read manifest data from string
    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = toml::Parser::new(&input);

        parser.parse()
              .ok_or(parser.errors.pop())
              .map_err(Option::unwrap)
              .map_err(From::from)
              .map(|data| Manifest { data: data })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use dependency::Dependency;
    use toml;

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let copy = manifest.clone();
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
        assert_eq!(manifest, copy);
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest { data: toml::Table::new() };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let other_dep = Dependency::new("other-dep").set_version("0.1.0");
        let _ = manifest.insert_into_table("dependencies", &other_dep);
        assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use err::size_assert_2d_for_field;

use self::rand::distributions::normal::StandardNormal;

use err::point_assert;

use std::f64::consts::PI;

pub fn torus_distance(field: &Vec<Vec<f64>>, point_1: &[usize; 2], point_2: &[usize; 2]) -> f64 {
    let size = field.capacity() - 1;

    point_assert(&field, &point_1);
    point_assert(&field, &point_2);

    let i: f64 = if point_1[0] >= point_2[0] {
        point_1[0] as f64 - point_2[0] as f64
    } else {
        point_2[0] as f64 - point_1[0] as f64
    };
    let j: f64 = if point_1[1] >= point_2[1] {
        point_1[1] as f64 - point_2[1] as f64
    } else {
        point_2[1] as f64 - point_1[1] as f64
    };

    let i: f64 = if i > (size as f64) / 2. {
        size as f64 - i
    } else {
        i
    };
    let j: f64 = if j > (size as f64) / 2. {
        size as f64 - j
    } else {
        j
    };

    let arg: f64 = i * i + j * j;

    arg.sqrt()
}

pub fn angle_for_vector_field(vx: &f64, vy: &f64) -> f64 {
    assert!(*vx != 0. && *vy != 0., "vx and vy equal zero");

    if *vx == 0. {
        if *vy > 0. {
            PI / 2.
        } else {
            -PI / 2.
        }
    } else {
        let tg: f64 = vy / vx;
        let mut phi = tg.atan();

        if *vx < 0. {
            if *vy > 0. {
                phi += PI
            } else {
                phi -= PI
            }
        }
        phi
    }
}

pub fn angle_for_tensor_field(q: &f64, u: &f64) -> f64 {
    assert!(*q != 0. && *u != 0., "q and u equal zero");

    if *q == 0. {
        if *u > 0. {
            PI / 4.
        } else {
            -PI / 4.
        }
    } else {
        let tg: f64 = u / q;
        let mut double_phi = tg.atan();

        if *q < 0. {
            if *u > 0. {
                double_phi += PI
            } else {
                double_phi -= PI
            }
        }
        double_phi / 2.
    }
}

pub fn j_mode_normalized(size: usize, j: usize) -> i32 {
    if j <= size / 2 {
        j as i32
    } else {
        j as i32 - size as i32
    }
}

pub fn fourier_distance(field: &Vec<Vec<f64>>, k1: usize, k2: usize) -> f64 {
    let size = field.capacity() - 1;

    size_assert_2d_for_field(&field);
    assert!(k1 < (size / 2 + 1));
    assert!(k2 < size);

    let d1 = k1 as f64;
    let d2 = if k2 as f64 <= size as f64 / 2. {
        k2 as f64
    } else {
        k2 as f64 - size as f64
    };

    (d1 * d1 + d2 * d2).sqrt()
}

#[inline]
pub fn normal_generator(mean: f64, std: f64) -> f64 {
    let StandardNormal(x) = rand::random();
    mean + x * std
}

#[inline]
pub fn normal_generator_max(mean: f64, std: f64, arg: f64, max_arg: f64) -> f64 {
    if arg > max_arg {
        mean
    } else {
        normal_generator(mean, std)
    }
}
<commit_msg>torus_distance_square method and small fixes<commit_after>extern crate rand;

use err::size_assert_2d_for_field;

use self::rand::distributions::normal::StandardNormal;

use err::point_assert;

use std::f64::consts::PI;

pub fn torus_distance(field: &Vec<Vec<f64>>, point_1: &[usize; 2], point_2: &[usize; 2]) -> f64 {
    let size = field.len() - 1;

    point_assert(&field, &point_1);
    point_assert(&field, &point_2);

    let i: f64 = if point_1[0] >= point_2[0] {
        point_1[0] as f64 - point_2[0] as f64
    } else {
        point_2[0] as f64 - point_1[0] as f64
    };
    let j: f64 = if point_1[1] >= point_2[1] {
        point_1[1] as f64 - point_2[1] as f64
    } else {
        point_2[1] as f64 - point_1[1] as f64
    };

    let i: f64 = if i > (size as f64) / 2. {
        size as f64 - i
    } else {
        i
    };
    let j: f64 = if j > (size as f64) / 2. {
        size as f64 - j
    } else {
        j
    };

    let arg: f64 = i * i + j * j;

    arg.sqrt()
}

pub fn torus_distance_square(field: &Vec<Vec<f64>>, point_1: &[usize; 2], point_2: &[usize; 2]) -> f64 {
    let size = field.len() - 1;

    point_assert(&field, &point_1);
    point_assert(&field, &point_2);

    let i: f64 = if point_1[0] >= point_2[0] {
        point_1[0] as f64 - point_2[0] as f64
    } else {
        point_2[0] as f64 - point_1[0] as f64
    };
    let j: f64 = if point_1[1] >= point_2[1] {
        point_1[1] as f64 - point_2[1] as f64
    } else {
        point_2[1] as f64 - point_1[1] as f64
    };

    let i: f64 = if i > (size as f64) / 2. {
        size as f64 - i
    } else {
        i
    };
    let j: f64 = if j > (size as f64) / 2. {
        size as f64 - j
    } else {
        j
    };

    let arg: f64 = i * i + j * j;

    arg
}

pub fn angle_for_vector_field(vx: &f64, vy: &f64) -> f64 {
    assert!(*vx != 0. && *vy != 0., "vx and vy equal zero");

    if *vx == 0. {
        if *vy > 0. {
            PI / 2.
        } else {
            -PI / 2.
        }
    } else {
        let tg: f64 = vy / vx;
        let mut phi = tg.atan();

        if *vx < 0. {
            if *vy > 0. {
                phi += PI
            } else {
                phi -= PI
            }
        }
        phi
    }
}

pub fn angle_for_tensor_field(q: &f64, u: &f64) -> f64 {
    assert!(*q != 0. && *u != 0., "q and u equal zero");

    if *q == 0. {
        if *u > 0. {
            PI / 4.
        } else {
            -PI / 4.
        }
    } else {
        let tg: f64 = u / q;
        let mut double_phi = tg.atan();

        if *q < 0. {
            if *u > 0. {
                double_phi += PI
            } else {
                double_phi -= PI
            }
        }
        double_phi / 2.
    }
}

pub fn j_mode_normalized(size: usize, j: usize) -> i32 {
    if j <= size / 2 {
        j as i32
    } else {
        j as i32 - size as i32
    }
}

pub fn fourier_distance(field: &Vec<Vec<f64>>, k1: usize, k2: usize) -> f64 {
    let size = field.len() - 1;

    size_assert_2d_for_field(&field);
    assert!(k1 < (size / 2 + 1));
    assert!(k2 < size);

    let d1 = k1 as f64;
    let d2 = if k2 as f64 <= size as f64 / 2. {
        k2 as f64
    } else {
        k2 as f64 - size as f64
    };

    (d1 * d1 + d2 * d2).sqrt()
}

#[inline]
pub fn normal_generator(mean: f64, std: f64) -> f64 {
    let StandardNormal(x) = rand::random();
    mean + x * std
}

#[inline]
pub fn normal_generator_max(mean: f64, std: f64, arg: f64, max_arg: f64) -> f64 {
    if arg > max_arg {
        mean
    } else {
        normal_generator(mean, std)
    }
}
<|endoftext|>


<commit_before>// check-pass

// This is issue #85435. But the real story is reflected in issue #85561, where
// a bug in the implementation of feature(capture_disjoint_fields) () was
// exposed to non-feature-gated code by a diagnostic changing PR that removed
// the gating in one case.

// This test is double-checking that the case of interest continues to work as
// expected in the *absence* of that feature gate. At the time of this writing,
// enabling the feature gate will cause this test to fail. We obviously cannot
// stabilize that feature until it can correctly handle this test.

fn main() {
    let val: u8 = 5;
    let u8_ptr: *const u8 = &val;
    let _closure = || {
        unsafe {
            let tmp = *u8_ptr;
            tmp

            // Just dereferencing and returning directly compiles fine:
            // *u8_ptr
        }
    };
}
<commit_msg>Apply suggestions from code review<commit_after>// check-pass
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck

// This is issue #85435. But the real story is reflected in issue #85561, where
// a bug in the implementation of feature(capture_disjoint_fields) () was
// exposed to non-feature-gated code by a diagnostic changing PR that removed
// the gating in one case.

// This test is double-checking that the case of interest continues to work as
// expected in the *absence* of that feature gate. At the time of this writing,
// enabling the feature gate will cause this test to fail. We obviously cannot
// stabilize that feature until it can correctly handle this test.

fn main() {
    let val: u8 = 5;
    let u8_ptr: *const u8 = &val;
    let _closure = || {
        unsafe {
            let tmp = *u8_ptr;
            tmp

            // Just dereferencing and returning directly compiles fine:
            // *u8_ptr
        }
    };
}
<|endoftext|>