<commit_before>use std::ops::{Fn, Mul, Add};
use context::{Context};
use tensor::{Tensor};
use node::{Graph};

pub struct Node<T> {
    id: &'static str,
    op: Box<Fn(Vec<Tensor<T>>) -> Tensor<T>>,
    op_train: Box<Fn(Vec<&Tensor<T>>) -> Tensor<T>>,
    op_prime: Box<Fn(&Tensor<T>, Vec<&Tensor<T>>) -> Vec<Tensor<T>>>,
    param: Vec<Box<Graph<T>>>,
}

impl <T> Node<T> {
    pub fn new(&self, node_id: &'static str, operation: Box<Fn(Vec<Tensor<T>>) -> Tensor<T>>, operation_train: Box<Fn(Vec<&Tensor<T>>) -> Tensor<T>>, operation_prime: Box<Fn(&Tensor<T>, Vec<&Tensor<T>>) -> Vec<Tensor<T>>>, parameter: Vec<Box<Graph<T>>>) -> Node<T> {
        Node {
            id: node_id,
            op: operation,
            op_train: operation_train,
            op_prime: operation_prime,
            param: parameter,
        }
    }
}

impl <T> Graph<T> for Node<T> where T: Copy + Mul<Output=T> + Add<Output=T> {
    fn get_id(&self) -> &'static str {
        self.id
    }

    fn run(&self, state: &Context<T>, variable: &Context<T>) -> Tensor<T> {
        (self.op)(self.param.iter().map(|node| node.run(state, variable)).collect())
    }

    fn train(&self, state: &Context<T>, variable: &Context<T>, history: &mut Context<T>) {
        let tensor = self.forward_pass(state, variable, history);
        history.set(self.get_id(), tensor);
    }

    fn forward_pass(&self, state: &Context<T>, variable: &Context<T>, history: &Context<T>) -> Tensor<T> {
        (self.op_train)(self.param.iter().map(|node| {
            node.forward_pass(state, variable, history);
            match history.get(node.get_id()) {
                Some(x) => x,
                None    => panic!("Node {} does not exist in history", node.get_id()),
            }
        }).collect())
    }

    fn backward_pass(&self, state: &mut Context<T>, variable: &Context<T>, history: &Context<T>, gradient: &Tensor<T>, learning_rate: &f64) {
        let deltas = (self.op_prime)(gradient, self.param.iter().map(|node| match history.get(node.get_id()) {
            Some(x) => x,
            None    => panic!("Node {} does not exist in history", node.get_id()),
        }).collect());
        for (delta, parameter) in deltas.iter().zip(self.param.iter()) {
            parameter.backward_pass(state, variable, history, delta, learning_rate);
        }
    }
}
<commit_msg>document node<commit_after>use std::ops::{Fn, Mul, Add};
use context::{Context};
use tensor::{Tensor};
use node::{Graph};

pub struct Node<T> {
    id: &'static str,
    op: Box<Fn(Vec<Tensor<T>>) -> Tensor<T>>,
    op_train: Box<Fn(Vec<&Tensor<T>>) -> Tensor<T>>,
    op_prime: Box<Fn(&Tensor<T>, Vec<&Tensor<T>>) -> Vec<Tensor<T>>>,
    param: Vec<Box<Graph<T>>>,
}

impl <T> Node<T> {
    /// computation node
    ///
    /// # Arguments
    ///
    /// if this node is z = f(x, y):
    ///
    /// - `node_id`
    /// - `operation` - f
    /// - `operation_train`
    /// - `operation_prime` - f_x,y which takes in a gradient dC/dz and inputs x, y; outputs gradients dC/dx, dC/dy
    /// - `parameter` - Vec<(x, y)>
    pub fn new(&self, node_id: &'static str, operation: Box<Fn(Vec<Tensor<T>>) -> Tensor<T>>, operation_train: Box<Fn(Vec<&Tensor<T>>) -> Tensor<T>>, operation_prime: Box<Fn(&Tensor<T>, Vec<&Tensor<T>>) -> Vec<Tensor<T>>>, parameter: Vec<Box<Graph<T>>>) -> Node<T> {
        Node {
            id: node_id,
            op: operation,
            op_train: operation_train,
            op_prime: operation_prime,
            param: parameter,
        }
    }
}

impl <T> Graph<T> for Node<T> where T: Copy + Mul<Output=T> + Add<Output=T> {
    fn get_id(&self) -> &'static str {
        self.id
    }

    fn run(&self, state: &Context<T>, variable: &Context<T>) -> Tensor<T> {
        (self.op)(self.param.iter().map(|node| node.run(state, variable)).collect())
    }

    fn train(&self, state: &Context<T>, variable: &Context<T>, history: &mut Context<T>) {
        let tensor = self.forward_pass(state, variable, history);
        history.set(self.get_id(), tensor);
    }

    fn forward_pass(&self, state: &Context<T>, variable: &Context<T>, history: &Context<T>) -> Tensor<T> {
        (self.op_train)(self.param.iter().map(|node| {
            node.forward_pass(state, variable, history);
            match history.get(node.get_id()) {
                Some(x) => x,
                None    => panic!("Node {} does not exist in history", node.get_id()),
            }
        }).collect())
    }

    fn backward_pass(&self, state: &mut Context<T>, variable: &Context<T>, history: &Context<T>, gradient: &Tensor<T>, learning_rate: &f64) {
        let deltas = (self.op_prime)(gradient, self.param.iter().map(|node| match history.get(node.get_id()) {
            Some(x) => x,
            None    => panic!("Node {} does not exist in history", node.get_id()),
        }).collect());
        for (delta, parameter) in deltas.iter().zip(self.param.iter()) {
            parameter.backward_pass(state, variable, history, delta, learning_rate);
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};
use std::path::{Path, PathBuf};

use crate::errors::*;

use crate::dist::temp;
use crate::utils::notify::NotificationLevel;

#[derive(Debug)]
pub enum Notification<'a> {
    Install(crate::dist::Notification<'a>),
    Utils(crate::utils::Notification<'a>),
    Temp(temp::Notification<'a>),

    SetDefaultToolchain(&'a str),
    SetOverrideToolchain(&'a Path, &'a str),
    SetProfile(&'a str),
    LookingForToolchain(&'a str),
    ToolchainDirectory(&'a Path, &'a str),
    UpdatingToolchain(&'a str),
    InstallingToolchain(&'a str),
    InstalledToolchain(&'a str),
    UsingExistingToolchain(&'a str),
    UninstallingToolchain(&'a str),
    UninstalledToolchain(&'a str),
    ToolchainNotInstalled(&'a str),
    UpdateHashMatches,
    UpgradingMetadata(&'a str, &'a str),
    MetadataUpgradeNotNeeded(&'a str),
    WritingMetadataVersion(&'a str),
    ReadMetadataVersion(&'a str),
    NonFatalError(&'a Error),
    UpgradeRemovesToolchains,
    MissingFileDuringSelfUninstall(PathBuf),
    PlainVerboseMessage(&'a str),
    /// Both `rust-toolchain` and `rust-toolchain.toml` exist within a directory
    DuplicateToolchainFile {
        rust_toolchain: &'a Path,
        rust_toolchain_toml: &'a Path,
    },
}

impl<'a> From<crate::dist::Notification<'a>> for Notification<'a> {
    fn from(n: crate::dist::Notification<'a>) -> Self {
        Notification::Install(n)
    }
}
impl<'a> From<crate::utils::Notification<'a>> for Notification<'a> {
    fn from(n: crate::utils::Notification<'a>) -> Self {
        Notification::Utils(n)
    }
}
impl<'a> From<temp::Notification<'a>> for Notification<'a> {
    fn from(n: temp::Notification<'a>) -> Self {
        Notification::Temp(n)
    }
}

impl<'a> Notification<'a> {
    pub fn level(&self) -> NotificationLevel {
        use self::Notification::*;
        match self {
            Install(n) => n.level(),
            Utils(n) => n.level(),
            Temp(n) => n.level(),
            ToolchainDirectory(_, _)
            | LookingForToolchain(_)
            | WritingMetadataVersion(_)
            | InstallingToolchain(_)
            | UpdatingToolchain(_)
            | ReadMetadataVersion(_)
            | InstalledToolchain(_)
            | PlainVerboseMessage(_)
            | UpdateHashMatches => NotificationLevel::Verbose,
            SetDefaultToolchain(_)
            | SetOverrideToolchain(_, _)
            | SetProfile(_)
            | UsingExistingToolchain(_)
            | UninstallingToolchain(_)
            | UninstalledToolchain(_)
            | ToolchainNotInstalled(_)
            | UpgradingMetadata(_, _)
            | MetadataUpgradeNotNeeded(_) => NotificationLevel::Info,
            NonFatalError(_) => NotificationLevel::Error,
            UpgradeRemovesToolchains
            | MissingFileDuringSelfUninstall(_)
            | DuplicateToolchainFile { .. } => NotificationLevel::Warn,
        }
    }
}

impl<'a> Display for Notification<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
        use self::Notification::*;
        match self {
            Install(n) => n.fmt(f),
            Utils(n) => n.fmt(f),
            Temp(n) => n.fmt(f),
            SetDefaultToolchain(name) => write!(f, "default toolchain set to '{}'", name),
            SetOverrideToolchain(path, name) => write!(
                f,
                "override toolchain for '{}' set to '{}'",
                path.display(),
                name
            ),
            SetProfile(name) => write!(f, "profile set to '{}'", name),
            LookingForToolchain(name) => write!(f, "looking for installed toolchain '{}'", name),
            ToolchainDirectory(path, _) => write!(f, "toolchain directory: '{}'", path.display()),
            UpdatingToolchain(name) => write!(f, "updating existing install for '{}'", name),
            InstallingToolchain(name) => write!(f, "installing toolchain '{}'", name),
            InstalledToolchain(name) => write!(f, "toolchain '{}' installed", name),
            UsingExistingToolchain(name) => write!(f, "using existing install for '{}'", name),
            UninstallingToolchain(name) => write!(f, "uninstalling toolchain '{}'", name),
            UninstalledToolchain(name) => write!(f, "toolchain '{}' uninstalled", name),
            ToolchainNotInstalled(name) => write!(f, "no toolchain installed for '{}'", name),
            UpdateHashMatches => write!(f, "toolchain is already up to date"),
            UpgradingMetadata(from_ver, to_ver) => write!(
                f,
                "upgrading metadata version from '{}' to '{}'",
                from_ver, to_ver
            ),
            MetadataUpgradeNotNeeded(ver) => write!(
                f,
                "nothing to upgrade: metadata version is already '{}'",
                ver
            ),
            WritingMetadataVersion(ver) => write!(f, "writing metadata version: '{}'", ver),
            ReadMetadataVersion(ver) => write!(f, "read metadata version: '{}'", ver),
            NonFatalError(e) => write!(f, "{}", e),
            UpgradeRemovesToolchains => write!(
                f,
                "this upgrade will remove all existing toolchains. you will need to reinstall them"
            ),
            MissingFileDuringSelfUninstall(p) => write!(
                f,
                "expected file does not exist to uninstall: {}",
                p.display()
            ),
            PlainVerboseMessage(r) => write!(f, "{}", r),
            DuplicateToolchainFile {
                rust_toolchain,
                rust_toolchain_toml,
            } => write!(
                f,
                "both `{0}` and `{1}` exist. Using `{0}`",
                rust_toolchain.display(),
                rust_toolchain_toml.display()
            ),
        }
    }
}
<commit_msg>Canonicalize another path for display<commit_after>use std::fmt::{self, Display};
use std::path::{Path, PathBuf};

use crate::errors::*;

use crate::dist::temp;
use crate::utils::notify::NotificationLevel;

#[derive(Debug)]
pub enum Notification<'a> {
    Install(crate::dist::Notification<'a>),
    Utils(crate::utils::Notification<'a>),
    Temp(temp::Notification<'a>),

    SetDefaultToolchain(&'a str),
    SetOverrideToolchain(&'a Path, &'a str),
    SetProfile(&'a str),
    LookingForToolchain(&'a str),
    ToolchainDirectory(&'a Path, &'a str),
    UpdatingToolchain(&'a str),
    InstallingToolchain(&'a str),
    InstalledToolchain(&'a str),
    UsingExistingToolchain(&'a str),
    UninstallingToolchain(&'a str),
    UninstalledToolchain(&'a str),
    ToolchainNotInstalled(&'a str),
    UpdateHashMatches,
    UpgradingMetadata(&'a str, &'a str),
    MetadataUpgradeNotNeeded(&'a str),
    WritingMetadataVersion(&'a str),
    ReadMetadataVersion(&'a str),
    NonFatalError(&'a Error),
    UpgradeRemovesToolchains,
    MissingFileDuringSelfUninstall(PathBuf),
    PlainVerboseMessage(&'a str),
    /// Both `rust-toolchain` and `rust-toolchain.toml` exist within a directory
    DuplicateToolchainFile {
        rust_toolchain: &'a Path,
        rust_toolchain_toml: &'a Path,
    },
}

impl<'a> From<crate::dist::Notification<'a>> for Notification<'a> {
    fn from(n: crate::dist::Notification<'a>) -> Self {
        Notification::Install(n)
    }
}
impl<'a> From<crate::utils::Notification<'a>> for Notification<'a> {
    fn from(n: crate::utils::Notification<'a>) -> Self {
        Notification::Utils(n)
    }
}
impl<'a> From<temp::Notification<'a>> for Notification<'a> {
    fn from(n: temp::Notification<'a>) -> Self {
        Notification::Temp(n)
    }
}

impl<'a> Notification<'a> {
    pub fn level(&self) -> NotificationLevel {
        use self::Notification::*;
        match self {
            Install(n) => n.level(),
            Utils(n) => n.level(),
            Temp(n) => n.level(),
            ToolchainDirectory(_, _)
            | LookingForToolchain(_)
            | WritingMetadataVersion(_)
            | InstallingToolchain(_)
            | UpdatingToolchain(_)
            | ReadMetadataVersion(_)
            | InstalledToolchain(_)
            | PlainVerboseMessage(_)
            | UpdateHashMatches => NotificationLevel::Verbose,
            SetDefaultToolchain(_)
            | SetOverrideToolchain(_, _)
            | SetProfile(_)
            | UsingExistingToolchain(_)
            | UninstallingToolchain(_)
            | UninstalledToolchain(_)
            | ToolchainNotInstalled(_)
            | UpgradingMetadata(_, _)
            | MetadataUpgradeNotNeeded(_) => NotificationLevel::Info,
            NonFatalError(_) => NotificationLevel::Error,
            UpgradeRemovesToolchains
            | MissingFileDuringSelfUninstall(_)
            | DuplicateToolchainFile { .. } => NotificationLevel::Warn,
        }
    }
}

impl<'a> Display for Notification<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
        use self::Notification::*;
        match self {
            Install(n) => n.fmt(f),
            Utils(n) => n.fmt(f),
            Temp(n) => n.fmt(f),
            SetDefaultToolchain(name) => write!(f, "default toolchain set to '{}'", name),
            SetOverrideToolchain(path, name) => write!(
                f,
                "override toolchain for '{}' set to '{}'",
                path.display(),
                name
            ),
            SetProfile(name) => write!(f, "profile set to '{}'", name),
            LookingForToolchain(name) => write!(f, "looking for installed toolchain '{}'", name),
            ToolchainDirectory(path, _) => write!(f, "toolchain directory: '{}'", path.display()),
            UpdatingToolchain(name) => write!(f, "updating existing install for '{}'", name),
            InstallingToolchain(name) => write!(f, "installing toolchain '{}'", name),
            InstalledToolchain(name) => write!(f, "toolchain '{}' installed", name),
            UsingExistingToolchain(name) => write!(f, "using existing install for '{}'", name),
            UninstallingToolchain(name) => write!(f, "uninstalling toolchain '{}'", name),
            UninstalledToolchain(name) => write!(f, "toolchain '{}' uninstalled", name),
            ToolchainNotInstalled(name) => write!(f, "no toolchain installed for '{}'", name),
            UpdateHashMatches => write!(f, "toolchain is already up to date"),
            UpgradingMetadata(from_ver, to_ver) => write!(
                f,
                "upgrading metadata version from '{}' to '{}'",
                from_ver, to_ver
            ),
            MetadataUpgradeNotNeeded(ver) => write!(
                f,
                "nothing to upgrade: metadata version is already '{}'",
                ver
            ),
            WritingMetadataVersion(ver) => write!(f, "writing metadata version: '{}'", ver),
            ReadMetadataVersion(ver) => write!(f, "read metadata version: '{}'", ver),
            NonFatalError(e) => write!(f, "{}", e),
            UpgradeRemovesToolchains => write!(
                f,
                "this upgrade will remove all existing toolchains. you will need to reinstall them"
            ),
            MissingFileDuringSelfUninstall(p) => write!(
                f,
                "expected file does not exist to uninstall: {}",
                p.display()
            ),
            PlainVerboseMessage(r) => write!(f, "{}", r),
            DuplicateToolchainFile {
                rust_toolchain,
                rust_toolchain_toml,
            } => write!(
                f,
                "both `{0}` and `{1}` exist. Using `{0}`",
                rust_toolchain
                    .canonicalize()
                    .unwrap_or_else(|_| PathBuf::from(rust_toolchain))
                    .display(),
                rust_toolchain_toml
                    .canonicalize()
                    .unwrap_or_else(|_| PathBuf::from(rust_toolchain_toml))
                    .display(),
            ),
        }
    }
}
<|endoftext|>


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

//! SPI configuration

/// Enables SPI interface on any of the 4 SSI (Synchronous Serial Interface) modules in TM4C microcontrollers

use core::intrinsics::abort;
use hal::tiva_c::sysctl;
use util::support::get_reg_ref;

#[path="../../util/ioreg.rs"]
#[macro_use] mod ioreg;
#[path="../../util/wait_for.rs"]
#[macro_use] mod wait_for;

/// There are 4 SSI instances an SPI interface can use
/// See the TM4C123GH6PM datasheet page 954 for detailed signal to pin mappings
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum SpiId {
  /// SPI over SSI0, uses pins PA2:5
  Spi0,

  /// SPI over SSI1, uses pins PF0:3 or PD0:3
  Spi1,

  /// SPI over SSI2, uses pins PB4:7
  Spi2,

  /// SPI over SSI3, uses pins PD0:3
  Spi3,
}

/**
SPI configuration object

Configuration object used when instantiating an SPI instance

Note: The SPI GPIO pins must be set up correctly before using SPI. For example, for a master-only TX and CK config on SSI0,
the platformtree section might look like the following (taken from a Tiva C configuration):

```
gpio {
  a {
    spi_ck@2 {
      direction = "out";
      function  = 2;
    }

    spi_tx@5 {
      direction = "out";
      function  = 2;
    }
  }
}
```
*/
pub struct SpiConf {
  /// Which SPI peripheral to use. The Tiva C has 4 SSI interfaces that can be used for SPI
  pub peripheral: SpiId,

  /// Bus frequency in Hz. Peripheral clock scaling is calculated from this value to a possibly non-exact match
  pub frequency: u32,
}

/**
Structure describing a single SPI interface

# Examples

Create an SPI interface on SSI0 with a run frequency of 4MHz

```
#![crate_type = "staticlib"]
#![feature(plugin, start, core_intrinsics)]
#![no_std]
#![plugin(macro_platformtree)]

extern crate zinc;

use zinc::hal::spi::Spi;
use zinc::hal::tiva_c::spi;

platformtree!(
  tiva_c@mcu {
    // Tiva C ends up with an 80MHz clock from 16MHz external xtal and x5 PLL
    clock {
      source = "MOSC";
      xtal   = "X16_0MHz";
      pll    = true;
      div    = 5;
    }

    gpio {
      a {
        spi_ck@2 {
          direction = "out";
          function  = 2;
        }

        spi_tx@5 {
          direction = "out";
          function  = 2;
        }
      }
    }
  }

  os {
    single_task {
      loop = "run";
    }
  }
);

fn run() {
  let spi = spi::Spi::new(spi::SpiConf {
    peripheral: spi::SpiId::Spi0,
    frequency: 4_000_000
  });

  loop {
    spi.write('a' as u8);
  }
}
```
*/
#[derive(Clone, Copy)]
pub struct Spi {
  /// SSI registers
  regs: &'static reg::Ssi,
}

impl Spi {
  /// Create and setup an SPI interface.
  pub fn new(config: SpiConf) -> Spi {

    let (periph, regs) = match config.peripheral {
      SpiId::Spi0 => (sysctl::periph::ssi::SSI_0, reg::SSI_0),
      SpiId::Spi1 => (sysctl::periph::ssi::SSI_1, reg::SSI_1),
      SpiId::Spi2 => (sysctl::periph::ssi::SSI_2, reg::SSI_2),
      SpiId::Spi3 => (sysctl::periph::ssi::SSI_3, reg::SSI_3),
    };

    let spi = Spi { regs: get_reg_ref(regs) };

    // Make sure peripheral clock gating is enabled
    periph.ensure_enabled();

    spi.configure(config);

    spi
  }

  /// Configure the SSI into SPI mode. Currently hard coded at 3.2MHz for 16MHz PIOSC
  fn configure(&self, config: SpiConf) {
    // Disable peripheral so we can configure it
    self.regs.ssicr1.set_sse(false);

    self.regs.ssicr1
      .set_sse(false)
      .set_ms(false)
      .set_lbm(false);

    // Set clock rate
    self.set_frequency(config.frequency);

    self.regs.ssicr0
      .set_sph(false)
      .set_spo(false)
      .set_frf(0)     // Put SSI into SPI mode
      .set_dss(0x7);  // 8 bit frames

    // Turn on peripheral now that we've configured it
    self.regs.ssicr1.set_sse(true);
  }

  /// Set SPI frequency
  ///
  /// This function computes the divisor and exponent (for lack of a better name). These are stored in `ssicpsr.cpsdvsr` and `ssicr0.scr` respectively.
  /// The clock rate formula (taken from the datasheet is) `ClockRate = SysClk / (CPSDVSR * (1 + SCR))` where SysClk is the system clock in Hz.
  fn set_frequency(&self, freq: u32) {
    let sysclk = sysctl::clock::sysclk_get() as u16;

    let mut divisor: u16 = 2;

    while divisor <= 254 {
      let prescale_hz: u16 = sysclk / divisor;

      // Calculate exponent
      let scr: u16 = ((prescale_hz as f32 / freq as f32) + 0.5f32) as u16;

      // Check we can support the divider
      if scr < 256 {
        self.regs.ssicpsr.set_cpsdvsr(divisor);

        self.regs.ssicr0.set_scr(scr - 1);

        return
      }

      divisor += 2;
    }

    // TODO(jamwaffles): Return a Result from here as well as the calling configure method
    unsafe { abort() };
  }

  /// Wait for SSI TX FIFO to be ready
  /// This checks the busy flag (0 = not busy) and the "transmit FIFO not full" flag (1 = not full)
  fn writeable(&self) -> bool {
    !self.regs.ssisr.bsy() && self.regs.ssisr.tnf()
  }

  /// Wait for SSI data buffer to be readable
  fn readable(&self) -> bool {
    !self.regs.ssisr.bsy()
  }
}

impl ::hal::spi::Spi for Spi {
  fn write(&self, value: u8) {
    wait_for!(self.writeable());

    self.regs.ssidr.set_data(value as u16);
  }

  fn read(&self) -> u8 {
    wait_for!(self.readable());

    self.regs.ssidr.data() as u8
  }
}

#[allow(missing_docs)]
pub mod reg {
  //! SSI registers definition
  use volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(Ssi = {
    /// SSI control register 0
    0x000 => reg16 ssicr0 {
      0..3 => dss: rw,    //= Data size select, 0x7 = 8 bits, see datasheet page 970 for other values
      4..5 => frf: rw,    //= Frame format, 0 = SPI 1 = TI SSF 2 Microwire
      6    => spo: rw,    //= SSI polarity, 0 = steady staate low on SSInCLK 1 = steady state high
      7    => sph: rw,    //= SSI clock phase, 1 = first edge 0 = second edge
      15..8 => scr: rw,   //= SSI clock rate, calculated from formula `SysClk / (CPSDVSR * (1 + SCR))`
    },

    /// SSI control register 1
    0x004 => reg16 ssicr1 {
      0 => lbm: rw,       //= Loopback enable, 1 = enabled 0 = normal operation
      1 => sse: rw,       //= Serial port enable 1 = enabled 0 = disabled. Must be cleared before SSI can be configured
      2 => ms: rw,        //= Master/slave select 0 = master 1 = slave
      4 => eot: rw,       //= End of transmission. Not sure what this is
    },

    /// SSI send/receive register
    /// When the SSIDR register is read, the entry in the receive FIFO that is pointed to by the current FIFO read pointer is accessed. When a data value is removed by the SSI receive logic from the incoming data frame, it is placed into the entry in the receive FIFO pointed to by the current FIFO write pointer.
    /// When the SSIDR register is written to, the entry in the transmit FIFO that is pointed to by the write pointer is written to. Data values are removed from the transmit FIFO one value at a time by the transmit logic. Each data value is loaded into the transmit serial shifter, then serially shifted out onto the SSInTx pin at the programmed bit rate.
    /// See page 973 in datasheet for more details
    0x008 => reg16 ssidr {
      0..15 => data: rw   //= Receive/transmit data
    },

    /// SSI status register
    0x00c => reg16 ssisr {
      0 => tfe: ro,       //= TX FIFO empty 1 = empty 0 = not empty
      1 => tnf: ro,       //= TX FIFO full 1 = not full 0 = full
      2 => rne: ro,       //= RX FIFO 1 = not empty 0 = empty
      3 => rff: ro,       //= RX FIFO full 0 = not full 1 = full
      4 => bsy: ro,       //= SSI busy 0 = idle, can send data 1 = transmitting, can't send data yet
    },

    /// SSI clock prescale register
    0x010 => reg16 ssicpsr {
      0..7 => cpsdvsr: rw //= SSI clock prescale divisor, 2 – 254 inclusive
    },

    /// SSI clock source configuration
    0xfc8 => reg16 ssicc {
      0..3 => cs: rw,     //= SSI baud clock source, 0x0 = system clock, 0x5 = PIOSC
    },
  });

  pub const SSI_0: *const Ssi = 0x40008000 as *const Ssi;
  pub const SSI_1: *const Ssi = 0x40009000 as *const Ssi;
  pub const SSI_2: *const Ssi = 0x4000A000 as *const Ssi;
  pub const SSI_3: *const Ssi = 0x4000B000 as *const Ssi;
}<commit_msg>Cast to u32 in freq calculation<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Lionel Flandrin <lionel@svkt.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! SPI configuration

/// Enables SPI interface on any of the 4 SSI (Synchronous Serial Interface) modules in TM4C microcontrollers

use core::intrinsics::abort;
use hal::tiva_c::sysctl;
use util::support::get_reg_ref;

#[path="../../util/ioreg.rs"]
#[macro_use] mod ioreg;
#[path="../../util/wait_for.rs"]
#[macro_use] mod wait_for;

/// There are 4 SSI instances an SPI interface can use
/// See the TM4C123GH6PM datasheet page 954 for detailed signal to pin mappings
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum SpiId {
  /// SPI over SSI0, uses pins PA2:5
  Spi0,

  /// SPI over SSI1, uses pins PF0:3 or PD0:3
  Spi1,

  /// SPI over SSI2, uses pins PB4:7
  Spi2,

  /// SPI over SSI3, uses pins PD0:3
  Spi3,
}

/**
SPI configuration object

Configuration object used when instantiating an SPI instance

Note: The SPI GPIO pins must be set up correctly before using SPI. For example, for a master-only TX and CK config on SSI0,
the platformtree section might look like the following (taken from a Tiva C configuration):

```
gpio {
  a {
    spi_ck@2 {
      direction = "out";
      function  = 2;
    }

    spi_tx@5 {
      direction = "out";
      function  = 2;
    }
  }
}
```
*/
pub struct SpiConf {
  /// Which SPI peripheral to use. The Tiva C has 4 SSI interfaces that can be used for SPI
  pub peripheral: SpiId,

  /// Bus frequency in Hz. Peripheral clock scaling is calculated from this value to a possibly non-exact match
  pub frequency: u32,
}

/**
Structure describing a single SPI interface

# Examples

Create an SPI interface on SSI0 with a run frequency of 4MHz

```
#![crate_type = "staticlib"]
#![feature(plugin, start, core_intrinsics)]
#![no_std]
#![plugin(macro_platformtree)]

extern crate zinc;

use zinc::hal::spi::Spi;
use zinc::hal::tiva_c::spi;

platformtree!(
  tiva_c@mcu {
    // Tiva C ends up with an 80MHz clock from 16MHz external xtal and x5 PLL
    clock {
      source = "MOSC";
      xtal   = "X16_0MHz";
      pll    = true;
      div    = 5;
    }

    gpio {
      a {
        spi_ck@2 {
          direction = "out";
          function  = 2;
        }

        spi_tx@5 {
          direction = "out";
          function  = 2;
        }
      }
    }
  }

  os {
    single_task {
      loop = "run";
    }
  }
);

fn run() {
  let spi = spi::Spi::new(spi::SpiConf {
    peripheral: spi::SpiId::Spi0,
    frequency: 4_000_000
  });

  loop {
    spi.write('a' as u8);
  }
}
```
*/
#[derive(Clone, Copy)]
pub struct Spi {
  /// SSI registers
  regs: &'static reg::Ssi,
}

impl Spi {
  /// Create and setup an SPI interface.
  pub fn new(config: SpiConf) -> Spi {

    let (periph, regs) = match config.peripheral {
      SpiId::Spi0 => (sysctl::periph::ssi::SSI_0, reg::SSI_0),
      SpiId::Spi1 => (sysctl::periph::ssi::SSI_1, reg::SSI_1),
      SpiId::Spi2 => (sysctl::periph::ssi::SSI_2, reg::SSI_2),
      SpiId::Spi3 => (sysctl::periph::ssi::SSI_3, reg::SSI_3),
    };

    let spi = Spi { regs: get_reg_ref(regs) };

    // Make sure peripheral clock gating is enabled
    periph.ensure_enabled();

    spi.configure(config);

    spi
  }

  /// Configure the SSI into SPI mode. Currently hard coded at 3.2MHz for 16MHz PIOSC
  fn configure(&self, config: SpiConf) {
    // Disable peripheral so we can configure it
    self.regs.ssicr1.set_sse(false);

    self.regs.ssicr1
      .set_sse(false)
      .set_ms(false)
      .set_lbm(false);

    // Set clock rate
    self.set_frequency(config.frequency);

    self.regs.ssicr0
      .set_sph(false)
      .set_spo(false)
      .set_frf(0)     // Put SSI into SPI mode
      .set_dss(0x7);  // 8 bit frames

    // Turn on peripheral now that we've configured it
    self.regs.ssicr1.set_sse(true);
  }

  /// Set SPI frequency
  ///
  /// This function computes the divisor and exponent (for lack of a better name). These are stored in `ssicpsr.cpsdvsr` and `ssicr0.scr` respectively.
  /// The clock rate formula (taken from the datasheet is) `ClockRate = SysClk / (CPSDVSR * (1 + SCR))` where SysClk is the system clock in Hz.
  fn set_frequency(&self, freq: u32) {
    let sysclk = sysctl::clock::sysclk_get() as u32;

    let mut divisor: u32 = 2;

    while divisor <= 254 {
      let prescale_hz = sysclk / divisor;

      // Calculate exponent
      let scr = ((prescale_hz as f32 / freq as f32) + 0.5f32) as u32;

      // Check we can support the divider
      if scr < 256 {
        self.regs.ssicpsr.set_cpsdvsr(divisor as u16);

        self.regs.ssicr0.set_scr((scr - 1) as u16);

        return
      }

      divisor += 2;
    }

    // TODO(jamwaffles): Return a Result from here as well as the calling configure method
    unsafe { abort() };
  }

  /// Wait for SSI TX FIFO to be ready
  /// This checks the busy flag (0 = not busy) and the "transmit FIFO not full" flag (1 = not full)
  fn writeable(&self) -> bool {
    !self.regs.ssisr.bsy() && self.regs.ssisr.tnf()
  }

  /// Wait for SSI data buffer to be readable
  fn readable(&self) -> bool {
    !self.regs.ssisr.bsy()
  }
}

impl ::hal::spi::Spi for Spi {
  fn write(&self, value: u8) {
    wait_for!(self.writeable());

    self.regs.ssidr.set_data(value as u16);
  }

  fn read(&self) -> u8 {
    wait_for!(self.readable());

    self.regs.ssidr.data() as u8
  }
}

#[allow(missing_docs)]
pub mod reg {
  //! SSI registers definition
  use volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(Ssi = {
    /// SSI control register 0
    0x000 => reg16 ssicr0 {
      0..3 => dss: rw,    //= Data size select, 0x7 = 8 bits, see datasheet page 970 for other values
      4..5 => frf: rw,    //= Frame format, 0 = SPI 1 = TI SSF 2 Microwire
      6    => spo: rw,    //= SSI polarity, 0 = steady staate low on SSInCLK 1 = steady state high
      7    => sph: rw,    //= SSI clock phase, 1 = first edge 0 = second edge
      15..8 => scr: rw,   //= SSI clock rate, calculated from formula `SysClk / (CPSDVSR * (1 + SCR))`
    },

    /// SSI control register 1
    0x004 => reg16 ssicr1 {
      0 => lbm: rw,       //= Loopback enable, 1 = enabled 0 = normal operation
      1 => sse: rw,       //= Serial port enable 1 = enabled 0 = disabled. Must be cleared before SSI can be configured
      2 => ms: rw,        //= Master/slave select 0 = master 1 = slave
      4 => eot: rw,       //= End of transmission. Not sure what this is
    },

    /// SSI send/receive register
    /// When the SSIDR register is read, the entry in the receive FIFO that is pointed to by the current FIFO read pointer is accessed. When a data value is removed by the SSI receive logic from the incoming data frame, it is placed into the entry in the receive FIFO pointed to by the current FIFO write pointer.
    /// When the SSIDR register is written to, the entry in the transmit FIFO that is pointed to by the write pointer is written to. Data values are removed from the transmit FIFO one value at a time by the transmit logic. Each data value is loaded into the transmit serial shifter, then serially shifted out onto the SSInTx pin at the programmed bit rate.
    /// See page 973 in datasheet for more details
    0x008 => reg16 ssidr {
      0..15 => data: rw   //= Receive/transmit data
    },

    /// SSI status register
    0x00c => reg16 ssisr {
      0 => tfe: ro,       //= TX FIFO empty 1 = empty 0 = not empty
      1 => tnf: ro,       //= TX FIFO full 1 = not full 0 = full
      2 => rne: ro,       //= RX FIFO 1 = not empty 0 = empty
      3 => rff: ro,       //= RX FIFO full 0 = not full 1 = full
      4 => bsy: ro,       //= SSI busy 0 = idle, can send data 1 = transmitting, can't send data yet
    },

    /// SSI clock prescale register
    0x010 => reg16 ssicpsr {
      0..7 => cpsdvsr: rw //= SSI clock prescale divisor, 2 – 254 inclusive
    },

    /// SSI clock source configuration
    0xfc8 => reg16 ssicc {
      0..3 => cs: rw,     //= SSI baud clock source, 0x0 = system clock, 0x5 = PIOSC
    },
  });

  pub const SSI_0: *const Ssi = 0x40008000 as *const Ssi;
  pub const SSI_1: *const Ssi = 0x40009000 as *const Ssi;
  pub const SSI_2: *const Ssi = 0x4000A000 as *const Ssi;
  pub const SSI_3: *const Ssi = 0x4000B000 as *const Ssi;
}<|endoftext|>


<commit_before>use iron::{Handler, IronResult, Request, Response, status};
use iron::headers::ContentType;
use iron::modifiers::{Header, RedirectRaw};
use std::env;

/// Handler for the root path, redirects to the Portier homepage.
pub struct Index;

impl Handler for Index {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::SeeOther, RedirectRaw("https://portier.github.io".to_string()))))
    }
}

/// Version information for the broker
pub struct Version;

impl Handler for Version {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        // TODO: Find a more robust way of detecting the git commit.
        // Maybe check/set it in build.rs? Fall back to HEROKU_SLUG_COMMIT?
        let version = env!("CARGO_PKG_VERSION");
        let sha = match env::var("HEROKU_SLUG_COMMIT") {
            Ok(sha) => sha,
            Err(_) => "unknown".to_string(),
        };
        let body = format!("Poriter {} (git commit {})", version, sha);

        Ok(Response::with((status::Ok, Header(ContentType::plaintext()), body)))
    }
}
<commit_msg>Fix typo in /ver.txt<commit_after>use iron::{Handler, IronResult, Request, Response, status};
use iron::headers::ContentType;
use iron::modifiers::{Header, RedirectRaw};
use std::env;

/// Handler for the root path, redirects to the Portier homepage.
pub struct Index;

impl Handler for Index {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::SeeOther, RedirectRaw("https://portier.github.io".to_string()))))
    }
}

/// Version information for the broker
pub struct Version;

impl Handler for Version {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        // TODO: Find a more robust way of detecting the git commit.
        // Maybe check/set it in build.rs? Fall back to HEROKU_SLUG_COMMIT?
        let version = env!("CARGO_PKG_VERSION");
        let sha = match env::var("HEROKU_SLUG_COMMIT") {
            Ok(sha) => sha,
            Err(_) => "unknown".to_string(),
        };
        let body = format!("Portier {} (git commit {})", version, sha);

        Ok(Response::with((status::Ok, Header(ContentType::plaintext()), body)))
    }
}
<|endoftext|>


<commit_before>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`] type is a smart pointer type. There can only be one owner of a
//! [`Box`], and the owner can decide to mutate the contents, which live on the
//! heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`] type is a non-threadsafe reference-counted pointer type intended
//! for sharing memory within a thread. An [`Rc`] pointer wraps a type, `T`, and
//! only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using [`Box`]) is too
//! constraining for an application, and is often paired with the [`Cell`] or
//! [`RefCell`] types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`] type is the threadsafe equivalent of the [`Rc`] type. It
//! provides all the same functionality of [`Rc`], except it requires that the
//! contained type `T` is shareable. Additionally, [`Arc<T>`][`Arc`] is itself
//! sendable while [`Rc<T>`][`Rc`] is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.
//!
//! [`Arc`]: sync
//! [`Box`]: boxed
//! [`Cell`]: core::cell
//! [`Rc`]: rc
//! [`RefCell`]: core::cell

#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
#![no_std]
#![needs_allocator]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![deny(unsafe_op_in_unsafe_fn)]
#![feature(rustc_allow_const_fn_unstable)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![cfg_attr(test, feature(new_uninit))]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_value_iter)]
#![feature(array_windows)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_btree_new)]
#![feature(const_fn)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
#![feature(const_cow_is_borrowed)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_range_pattern)]
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
#![feature(int_bits_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(maybe_uninit_ref)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(auto_traits)]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(range_bounds_assert_len)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![cfg_attr(bootstrap, feature(min_const_generics))]
#![feature(min_specialization)]
#![feature(set_ptr_value)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(staged_api)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
#![feature(unsized_fn_params)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
#![feature(alloc_layout_extra)]
#![feature(trusted_random_access)]
#![feature(try_trait)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
#![feature(slice_group_by)]
#![feature(decl_macro)]
// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
pub mod borrow;
pub mod collections;
pub mod fmt;
pub mod prelude;
pub mod raw_vec;
pub mod rc;
pub mod slice;
pub mod str;
pub mod string;
#[cfg(target_has_atomic = "ptr")]
pub mod sync;
#[cfg(target_has_atomic = "ptr")]
pub mod task;
#[cfg(test)]
mod tests;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops; // RangeFull
}

#[doc(hidden)]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
pub mod __export {
    pub use core::format_args;

    /// Force AST node to an expression to improve diagnostics in pattern position.
    #[rustc_macro_transparency = "semitransparent"]
    #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
    pub macro force_expr($e:expr) {
        $e
    }
}
<commit_msg>Rollup merge of #81112 - m-ou-se:alloc-std-ops-reexport, r=KodrAus<commit_after>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`] type is a smart pointer type. There can only be one owner of a
//! [`Box`], and the owner can decide to mutate the contents, which live on the
//! heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`] type is a non-threadsafe reference-counted pointer type intended
//! for sharing memory within a thread. An [`Rc`] pointer wraps a type, `T`, and
//! only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using [`Box`]) is too
//! constraining for an application, and is often paired with the [`Cell`] or
//! [`RefCell`] types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`] type is the threadsafe equivalent of the [`Rc`] type. It
//! provides all the same functionality of [`Rc`], except it requires that the
//! contained type `T` is shareable. Additionally, [`Arc<T>`][`Arc`] is itself
//! sendable while [`Rc<T>`][`Rc`] is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.
//!
//! [`Arc`]: sync
//! [`Box`]: boxed
//! [`Cell`]: core::cell
//! [`Rc`]: rc
//! [`RefCell`]: core::cell

#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
#![no_std]
#![needs_allocator]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![deny(unsafe_op_in_unsafe_fn)]
#![feature(rustc_allow_const_fn_unstable)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![cfg_attr(test, feature(new_uninit))]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_value_iter)]
#![feature(array_windows)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_btree_new)]
#![feature(const_fn)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
#![feature(const_cow_is_borrowed)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_range_pattern)]
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
#![feature(int_bits_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(maybe_uninit_ref)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(auto_traits)]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(range_bounds_assert_len)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![cfg_attr(bootstrap, feature(min_const_generics))]
#![feature(min_specialization)]
#![feature(set_ptr_value)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(staged_api)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
#![feature(unsized_fn_params)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
#![feature(alloc_layout_extra)]
#![feature(trusted_random_access)]
#![feature(try_trait)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
#![feature(slice_group_by)]
#![feature(decl_macro)]
// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
pub mod borrow;
pub mod collections;
pub mod fmt;
pub mod prelude;
pub mod raw_vec;
pub mod rc;
pub mod slice;
pub mod str;
pub mod string;
#[cfg(target_has_atomic = "ptr")]
pub mod sync;
#[cfg(target_has_atomic = "ptr")]
pub mod task;
#[cfg(test)]
mod tests;
pub mod vec;

#[doc(hidden)]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
pub mod __export {
    pub use core::format_args;

    /// Force AST node to an expression to improve diagnostics in pattern position.
    #[rustc_macro_transparency = "semitransparent"]
    #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
    pub macro force_expr($e:expr) {
        $e
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::objects::{MimirObject, Admin};
use chrono;
use regex;
use hyper;
use hyper::status::StatusCode;
use rs_es::error::EsError;
use rs_es;
use rs_es::EsResponse;
use serde_json;
use rs_es::operations::search::ScanResult;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use rs_es::units::Duration;

const SYNONYMS: [&'static str; 17] = ["cc,centre commercial",
                                      "hotel de ville,mairie",
                                      "gare sncf,gare",
                                      "chu,chr,hopital",
                                      "ld,lieu-dit",
                                      "st,saint",
                                      "ste,sainte",
                                      "bvd,bld,bd,boulevard",
                                      "pt,pont",
                                      "rle,ruelle",
                                      "rte,route",
                                      "vla,villa",
                                      "grand-champ,grandchamp",
                                      "fac,faculte,ufr,universite",
                                      "embarcadere,gare maritime",
                                      "cpam,securite sociale",
                                      "anpe,pole emploi"];

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    es_client: rs_es::Client,
    // some operation are not implemented in rs_es, we need to use a raw http client
    http_client: hyper::client::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_type_and_dataset_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

/// return the index associated to the given type
/// this will be an alias over another real index
fn get_main_type_index(doc_type: &str) -> String {
    format!("munin_{}", doc_type)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap().as_str();
        let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber {
            es_client: rs_es::Client::new(&host, port),
            http_client: hyper::client::Client::new(),
        }
    }

    pub fn get(&self, path: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a get on {}", path);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .get(&url)
            .send());
        rs_es::do_req(result)
    }
    fn put(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a put on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .put(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }
    fn post(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a post on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .post(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S_%f");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        info!("creating index {}", index_name);
        self.create_index(&index_name.to_string()).map(|_| index_name)
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        debug!("creating index");
        // Note: in rs_es it can be done with MappingOperation but for the moment I think
        // storing the mapping in json is more convenient
        let analysis = include_str!("../../../json/settings.json");

        let mut analysis_json_value = try!(serde_json::from_str::<serde_json::Value>(&analysis)
            .map_err(|err| format!("{}", err)));

        let synonyms: Vec<_> = SYNONYMS.to_vec()
            .into_iter()
            .map(|s| serde_json::Value::String(s.to_string()))
            .collect();

        *analysis_json_value.pointer_mut("/settings/analysis/filter/synonym_filter/synonyms")
            .unwrap() = serde_json::Value::Array(synonyms);

        self.put(name, &analysis_json_value.to_string())
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                Err(format!("cannot create index: {:?}", res))
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {
        let base_index = get_main_type_and_dataset_index(doc_type, dataset);
        self.get(&format!("{}/_aliases", base_index))
            .map_err(|e| e.to_string())
            .and_then(|res| match res.status {
                StatusCode::Ok => {
                    let value: serde_json::Value = try!(res.read_response()
                        .map_err(|e| e.to_string()));
                    Ok(value.as_object()
                        .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                        .unwrap_or_else(|| {
                            info!("no previous index to delete for type {} and dataset {}",
                                  doc_type,
                                  dataset);
                            vec![]
                        }))
                }
                StatusCode::NotFound => {
                    info!("impossible to find alias {}, no last index to remove",
                          base_index);
                    Ok(vec![])
                }
                _ => Err(format!("invalid elasticsearch response: {:?}", res)),
            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String,
                         is_geo_data: bool)
                         -> Result<(), String> {
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));

        let dataset_index = get_main_type_and_dataset_index(doc_type, dataset);
        try!(self.alias(&dataset_index, &vec![index.clone()], &last_indexes));

        let type_index = get_main_type_index(doc_type);
        try!(self.alias(&type_index, &vec![dataset_index.clone()], &last_indexes));

        if is_geo_data {
            try!(self.alias("munin_geo_data", &vec![type_index.to_string()], &vec![]));
            try!(self.alias("munin", &vec!["munin_geo_data".to_string()], &vec![]));
        } else {
            try!(self.alias("munin", &vec![type_index.to_string()], &vec![]));
        }
        for i in last_indexes {
            try!(self.delete_index(&i));
        }
        Ok(())
    }

    pub fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        self.get(&name)
            .map_err(|e| e.to_string())
            .map(|res| res.status == StatusCode::Ok)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        info!("for {}, adding alias {:?}, removing {:?}",
              alias,
              add,
              remove);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations =
            AliasOperations { actions: add_operations.chain(remove_operations).collect() };
        let json = serde_json::to_string(&operations).unwrap();
        self.post("_aliases", &json)
            .map_err(|e| e.to_string())
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                error!("failed to change aliases for {}, es response: {:?}",
                       alias,
                       res);
                Err(format!("failed to post aliases for {}: {:?}", alias, res).to_string())
            })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.es_client
            .delete_index(&index)
            .map(|res| res.acknowledged)
            .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            iter: I)
                            -> Result<usize, rs_es::error::EsError>
        where T: MimirObject,
              I: Iterator<Item = T>
    {
        use rs_es::operations::bulk::Action;
        let mut nb = 0;
        let chunk_size = 1000;
        // fold is used for creating the action and optionally set the id of the object
        let mut actions = iter.map(|v| {
            v.es_id()
                .into_iter()
                .fold(Action::index(v), |action, id| action.with_id(id))
        });
        loop {
            let chunk = actions.by_ref().take(chunk_size).collect::<Vec<_>>();
            nb += chunk.len();
            try!(self.es_client
                .bulk(&chunk)
                .with_index(&index)
                .with_doc_type(T::doc_type())
                .send());

            if chunk.len() < chunk_size {
                break;
            }
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, dataset: &str, iter: I) -> Result<usize, String>
        where T: MimirObject,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = try!(self.make_index(T::doc_type(), dataset));
        let nb_elements = try!(self.bulk_index(&index, iter).map_err(|e| e.to_string()));
        try!(self.publish_index(T::doc_type(), dataset, index, T::is_geo_data()));
        Ok(nb_elements)
    }

    pub fn get_admins_from_dataset(&mut self,
                                   dataset: &str)
                                   -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_and_dataset_index(Admin::doc_type(), dataset))
    }

    pub fn get_all_admins(&mut self) -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_index(Admin::doc_type()))
    }

    fn get_admins_from_index(&mut self, index: &str) -> Result<Vec<Admin>, rs_es::error::EsError> {
        let mut result: Vec<Admin> = vec![];
        let mut scan: ScanResult<Admin> = try!(self.es_client
            .search_query()
            .with_indexes(&[&index])
            .with_size(1000)
            .with_types(&[&Admin::doc_type()])
            .scan(&Duration::minutes(1)));
        loop {
            let page = try!(scan.scroll(&mut self.es_client, &Duration::minutes(1)));
            if page.hits.hits.len() == 0 {
                break;
            }
            result.extend(page.hits.hits.into_iter().filter_map(|hit| hit.source).map(|ad| *ad));
        }
        try!(scan.close(&mut self.es_client));
        Ok(result)
    }
}

#[test]
pub fn test_valid_url() {
    Rubber::new("http://localhost:9200");
    Rubber::new("localhost:9200");
}

#[test]
#[should_panic]
pub fn test_invalid_url() {
    Rubber::new("http://bob");
}

#[test]
#[should_panic]
pub fn test_invalid_url_no_port() {
    Rubber::new("localhost");
}
<commit_msg>simplify synonym collect<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program 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
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::objects::{MimirObject, Admin};
use chrono;
use regex;
use hyper;
use hyper::status::StatusCode;
use rs_es::error::EsError;
use rs_es;
use rs_es::EsResponse;
use serde_json;
use rs_es::operations::search::ScanResult;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use rs_es::units::Duration;

const SYNONYMS: [&'static str; 17] = ["cc,centre commercial",
                                      "hotel de ville,mairie",
                                      "gare sncf,gare",
                                      "chu,chr,hopital",
                                      "ld,lieu-dit",
                                      "st,saint",
                                      "ste,sainte",
                                      "bvd,bld,bd,boulevard",
                                      "pt,pont",
                                      "rle,ruelle",
                                      "rte,route",
                                      "vla,villa",
                                      "grand-champ,grandchamp",
                                      "fac,faculte,ufr,universite",
                                      "embarcadere,gare maritime",
                                      "cpam,securite sociale",
                                      "anpe,pole emploi"];

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    es_client: rs_es::Client,
    // some operation are not implemented in rs_es, we need to use a raw http client
    http_client: hyper::client::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_type_and_dataset_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

/// return the index associated to the given type
/// this will be an alias over another real index
fn get_main_type_index(doc_type: &str) -> String {
    format!("munin_{}", doc_type)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap().as_str();
        let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber {
            es_client: rs_es::Client::new(&host, port),
            http_client: hyper::client::Client::new(),
        }
    }

    pub fn get(&self, path: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a get on {}", path);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .get(&url)
            .send());
        rs_es::do_req(result)
    }
    fn put(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a put on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .put(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }
    fn post(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a post on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .post(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S_%f");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        info!("creating index {}", index_name);
        self.create_index(&index_name.to_string()).map(|_| index_name)
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        debug!("creating index");
        // Note: in rs_es it can be done with MappingOperation but for the moment I think
        // storing the mapping in json is more convenient
        let analysis = include_str!("../../../json/settings.json");

        let mut analysis_json_value = try!(serde_json::from_str::<serde_json::Value>(&analysis)
            .map_err(|err| format!("{}", err)));

        let synonyms: Vec<_> = SYNONYMS.iter()
            .map(|s| serde_json::Value::String(s.to_string()))
            .collect();

        *analysis_json_value.pointer_mut("/settings/analysis/filter/synonym_filter/synonyms")
            .unwrap() = serde_json::Value::Array(synonyms);

        self.put(name, &analysis_json_value.to_string())
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                Err(format!("cannot create index: {:?}", res))
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {
        let base_index = get_main_type_and_dataset_index(doc_type, dataset);
        self.get(&format!("{}/_aliases", base_index))
            .map_err(|e| e.to_string())
            .and_then(|res| match res.status {
                StatusCode::Ok => {
                    let value: serde_json::Value = try!(res.read_response()
                        .map_err(|e| e.to_string()));
                    Ok(value.as_object()
                        .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                        .unwrap_or_else(|| {
                            info!("no previous index to delete for type {} and dataset {}",
                                  doc_type,
                                  dataset);
                            vec![]
                        }))
                }
                StatusCode::NotFound => {
                    info!("impossible to find alias {}, no last index to remove",
                          base_index);
                    Ok(vec![])
                }
                _ => Err(format!("invalid elasticsearch response: {:?}", res)),
            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String,
                         is_geo_data: bool)
                         -> Result<(), String> {
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));

        let dataset_index = get_main_type_and_dataset_index(doc_type, dataset);
        try!(self.alias(&dataset_index, &vec![index.clone()], &last_indexes));

        let type_index = get_main_type_index(doc_type);
        try!(self.alias(&type_index, &vec![dataset_index.clone()], &last_indexes));

        if is_geo_data {
            try!(self.alias("munin_geo_data", &vec![type_index.to_string()], &vec![]));
            try!(self.alias("munin", &vec!["munin_geo_data".to_string()], &vec![]));
        } else {
            try!(self.alias("munin", &vec![type_index.to_string()], &vec![]));
        }
        for i in last_indexes {
            try!(self.delete_index(&i));
        }
        Ok(())
    }

    pub fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        self.get(&name)
            .map_err(|e| e.to_string())
            .map(|res| res.status == StatusCode::Ok)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        info!("for {}, adding alias {:?}, removing {:?}",
              alias,
              add,
              remove);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations =
            AliasOperations { actions: add_operations.chain(remove_operations).collect() };
        let json = serde_json::to_string(&operations).unwrap();
        self.post("_aliases", &json)
            .map_err(|e| e.to_string())
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                error!("failed to change aliases for {}, es response: {:?}",
                       alias,
                       res);
                Err(format!("failed to post aliases for {}: {:?}", alias, res).to_string())
            })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.es_client
            .delete_index(&index)
            .map(|res| res.acknowledged)
            .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            iter: I)
                            -> Result<usize, rs_es::error::EsError>
        where T: MimirObject,
              I: Iterator<Item = T>
    {
        use rs_es::operations::bulk::Action;
        let mut nb = 0;
        let chunk_size = 1000;
        // fold is used for creating the action and optionally set the id of the object
        let mut actions = iter.map(|v| {
            v.es_id()
                .into_iter()
                .fold(Action::index(v), |action, id| action.with_id(id))
        });
        loop {
            let chunk = actions.by_ref().take(chunk_size).collect::<Vec<_>>();
            nb += chunk.len();
            try!(self.es_client
                .bulk(&chunk)
                .with_index(&index)
                .with_doc_type(T::doc_type())
                .send());

            if chunk.len() < chunk_size {
                break;
            }
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, dataset: &str, iter: I) -> Result<usize, String>
        where T: MimirObject,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = try!(self.make_index(T::doc_type(), dataset));
        let nb_elements = try!(self.bulk_index(&index, iter).map_err(|e| e.to_string()));
        try!(self.publish_index(T::doc_type(), dataset, index, T::is_geo_data()));
        Ok(nb_elements)
    }

    pub fn get_admins_from_dataset(&mut self,
                                   dataset: &str)
                                   -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_and_dataset_index(Admin::doc_type(), dataset))
    }

    pub fn get_all_admins(&mut self) -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_index(Admin::doc_type()))
    }

    fn get_admins_from_index(&mut self, index: &str) -> Result<Vec<Admin>, rs_es::error::EsError> {
        let mut result: Vec<Admin> = vec![];
        let mut scan: ScanResult<Admin> = try!(self.es_client
            .search_query()
            .with_indexes(&[&index])
            .with_size(1000)
            .with_types(&[&Admin::doc_type()])
            .scan(&Duration::minutes(1)));
        loop {
            let page = try!(scan.scroll(&mut self.es_client, &Duration::minutes(1)));
            if page.hits.hits.len() == 0 {
                break;
            }
            result.extend(page.hits.hits.into_iter().filter_map(|hit| hit.source).map(|ad| *ad));
        }
        try!(scan.close(&mut self.es_client));
        Ok(result)
    }
}

#[test]
pub fn test_valid_url() {
    Rubber::new("http://localhost:9200");
    Rubber::new("localhost:9200");
}

#[test]
#[should_panic]
pub fn test_invalid_url() {
    Rubber::new("http://bob");
}

#[test]
#[should_panic]
pub fn test_invalid_url_no_port() {
    Rubber::new("localhost");
}
<|endoftext|>


<commit_before>//! string handles parsing of GPX-spec strings.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use parser::verify_starting_tag;
use parser::Context;

/// consume consumes a single string as tag content.
pub fn consume<R: Read>(
    context: &mut Context<R>,
    tagname: &'static str,
    allow_empty: bool,
) -> Result<String> {
    let mut string: Option<String> = None;
    if allow_empty {
        string = Some("".to_string());
    }
    verify_starting_tag(context, tagname)?;

    for event in context.reader() {
        match event.chain_err(|| "error while parsing XML")? {
            XmlEvent::StartElement { ref name, .. } => {
                bail!(ErrorKind::InvalidChildElement(
                    name.local_name.clone(),
                    tagname
                ));
            }
            XmlEvent::Characters(content) => string = Some(content),
            XmlEvent::EndElement { ref name } => {
                ensure!(
                    name.local_name == tagname,
                    ErrorKind::InvalidClosingTag(name.local_name.clone(), tagname)
                );
                return string.ok_or("no content inside string".into());
            }
            _ => {}
        }
    }
    bail!(ErrorKind::MissingClosingTag(tagname));
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;

    use super::consume;
    use GpxVersion;

    #[test]
    fn consume_simple_string() {
        let result = consume!(
            "<string>hello world</string>",
            GpxVersion::Gpx11,
            "string",
            false
        );

        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "hello world");
    }

    #[test]
    fn consume_new_tag() {
        // cannot start new tag inside string
        let result = consume!("<foo>bar<baz></baz></foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_start_tag() {
        // must have starting tag
        let result = consume!("bar</foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_end_tag() {
        // must have ending tag
        let result = consume!("<foo>bar", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_no_body() {
        // must have string content
        let result = consume!("<foo></foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_different_ending_tag() {
        // this is just illegal
        let result = consume!("<foo></foobar>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }
}
<commit_msg>Move string's allow_empty test to end and remove Option<String><commit_after>//! string handles parsing of GPX-spec strings.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use parser::verify_starting_tag;
use parser::Context;

/// consume consumes a single string as tag content.
pub fn consume<R: Read>(
    context: &mut Context<R>,
    tagname: &'static str,
    allow_empty: bool,
) -> Result<String> {
    verify_starting_tag(context, tagname)?;
    let mut string = String::new();

    for event in context.reader() {
        match event.chain_err(|| "error while parsing XML")? {
            XmlEvent::StartElement { ref name, .. } => {
                bail!(ErrorKind::InvalidChildElement(
                    name.local_name.clone(),
                    tagname
                ));
            }
            XmlEvent::Characters(content) => string = content,
            XmlEvent::EndElement { ref name } => {
                ensure!(
                    name.local_name == tagname,
                    ErrorKind::InvalidClosingTag(name.local_name.clone(), tagname)
                );
                if allow_empty || !string.is_empty() {
                    return Ok(string);
                }
                bail!("no content inside string");
            }
            _ => {}
        }
    }
    bail!(ErrorKind::MissingClosingTag(tagname));
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;

    use super::consume;
    use GpxVersion;

    #[test]
    fn consume_simple_string() {
        let result = consume!(
            "<string>hello world</string>",
            GpxVersion::Gpx11,
            "string",
            false
        );

        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "hello world");
    }

    #[test]
    fn consume_new_tag() {
        // cannot start new tag inside string
        let result = consume!("<foo>bar<baz></baz></foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_start_tag() {
        // must have starting tag
        let result = consume!("bar</foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_end_tag() {
        // must have ending tag
        let result = consume!("<foo>bar", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_no_body() {
        // must have string content
        let result = consume!("<foo></foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_different_ending_tag() {
        // this is just illegal
        let result = consume!("<foo></foobar>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }
}
<|endoftext|>


<commit_before>//! VM errors

use bigint::{Address, U256};

#[derive(Debug, Clone)]
/// Errors when trying to validate the transaction.
pub enum PreExecutionError {
    /// The caller is invalid.
    InvalidCaller,
    /// Nonce of the caller does not equal.
    InvalidNonce,
    /// Balance from the caller is insufficient.
    InsufficientBalance,
    /// Gas limit is smaller than the intrinsic gas required.
    InsufficientGasLimit,
}

#[derive(Debug, Clone)]
pub enum OnChainError {
    /// Stack is overflowed (pushed more than 1024 items to the
    /// stack).
    StackOverflow,
    /// Stack is underflowed (poped an empty stack).
    StackUnderflow,
    /// The opcode is invalid and the PC is not able to convert it to
    /// an instruction.
    InvalidOpcode,
    /// PC jumped to an invalid jump destination.
    BadJumpDest,
    /// PC overflowed (tries to read the next opcode which is already
    /// the end of the code). In Yellow Paper, this is categorized the
    /// same as InvalidOpcode.
    PCOverflow,
    /// Not enough gas to continue.
    EmptyGas,
    /// For instruction that requires reading a range, it is
    /// invalid. This in the Yellow Paper is covered by EmptyGas.
    InvalidRange,
}

impl From<OnChainError> for RuntimeError {
    fn from(val: OnChainError) -> RuntimeError {
        RuntimeError::OnChain(val)
    }
}

impl From<OnChainError> for EvalOnChainError {
    fn from(val: OnChainError) -> EvalOnChainError {
        EvalOnChainError::OnChain(val)
    }
}

impl From<OnChainError> for EvalError {
    fn from(val: OnChainError) -> EvalError {
        EvalError::OnChain(val)
    }
}

#[derive(Debug, Clone)]
pub enum NotSupportedError {
    /// The PC index is too large for the implementation of the VM to
    /// handle.
    PCIndexNotSupported,
    /// The memory index is too large for the implementation of the VM to
    /// handle.
    MemoryIndexNotSupported,
}

impl From<NotSupportedError> for RuntimeError {
    fn from(val: NotSupportedError) -> RuntimeError {
        RuntimeError::NotSupported(val)
    }
}

impl From<NotSupportedError> for EvalError {
    fn from(val: NotSupportedError) -> EvalError {
        EvalError::NotSupported(val)
    }
}

#[derive(Debug, Clone)]
pub enum RuntimeError {
    /// On chain error.
    OnChain(OnChainError),
    /// Off chain error due to VM not supported.
    NotSupported(NotSupportedError),
}

impl From<RuntimeError> for EvalError {
    fn from(val: RuntimeError) -> EvalError {
        match val {
            RuntimeError::OnChain(err) =>
                EvalError::OnChain(err),
            RuntimeError::NotSupported(err) =>
                EvalError::NotSupported(err),
        }
    }
}

#[derive(Debug, Clone)]
pub enum EvalOnChainError {
    OnChain(OnChainError),
    Require(RequireError),
}

impl From<EvalOnChainError> for EvalError {
    fn from(val: EvalOnChainError) -> EvalError {
        match val {
            EvalOnChainError::OnChain(err) =>
                EvalError::OnChain(err),
            EvalOnChainError::Require(err) =>
                EvalError::Require(err),
        }
    }
}

#[derive(Debug, Clone)]
pub enum EvalError {
    OnChain(OnChainError),
    NotSupported(NotSupportedError),
    Require(RequireError),
}

#[derive(Debug, Clone)]
/// Errors stating that the VM requires additional information to
/// continue running.
pub enum RequireError {
    /// Requires the account at address for the VM to continue
    /// running, this should usually be dealt by
    /// `vm.commit_account(AccountCommitment::Full { .. })` or
    /// `vm.commit_account(AccountCommitment::Nonexist(..))`.
    Account(Address),
    /// Requires the account code at address for the VM to continue
    /// running, this should usually be dealt by
    /// `vm.commit_account(AccountCommitment::Code { .. })`.
    AccountCode(Address),
    /// Requires the current value of the storage for the VM to
    /// continue running, this should usually be dealt by
    /// `vm.commit_account(AccountCommitment::Storage { .. }`.
    AccountStorage(Address, U256),
    /// Requires the blockhash for the VM to continue running, this
    /// should usually be dealt by `vm.commit_blockhash(..)`.
    Blockhash(U256),
}

impl From<RequireError> for EvalError {
    fn from(val: RequireError) -> EvalError {
        EvalError::Require(val)
    }
}

impl From<RequireError> for EvalOnChainError {
    fn from(val: RequireError) -> EvalOnChainError {
        EvalOnChainError::Require(val)
    }
}

#[derive(Debug, Clone)]
/// Errors returned when committing a new information.
pub enum CommitError {
    /// The commitment is invalid.
    InvalidCommitment,
    /// The commitment has already been committed.
    AlreadyCommitted,
}
<commit_msg>Problem: PCIndexNotSupported error is not used.<commit_after>//! VM errors

use bigint::{Address, U256};

#[derive(Debug, Clone)]
/// Errors when trying to validate the transaction.
pub enum PreExecutionError {
    /// The caller is invalid.
    InvalidCaller,
    /// Nonce of the caller does not equal.
    InvalidNonce,
    /// Balance from the caller is insufficient.
    InsufficientBalance,
    /// Gas limit is smaller than the intrinsic gas required.
    InsufficientGasLimit,
}

#[derive(Debug, Clone)]
pub enum OnChainError {
    /// Stack is overflowed (pushed more than 1024 items to the
    /// stack).
    StackOverflow,
    /// Stack is underflowed (poped an empty stack).
    StackUnderflow,
    /// The opcode is invalid and the PC is not able to convert it to
    /// an instruction.
    InvalidOpcode,
    /// PC jumped to an invalid jump destination.
    BadJumpDest,
    /// PC overflowed (tries to read the next opcode which is already
    /// the end of the code). In Yellow Paper, this is categorized the
    /// same as InvalidOpcode.
    PCOverflow,
    /// Not enough gas to continue.
    EmptyGas,
    /// For instruction that requires reading a range, it is
    /// invalid. This in the Yellow Paper is covered by EmptyGas.
    InvalidRange,
}

impl From<OnChainError> for RuntimeError {
    fn from(val: OnChainError) -> RuntimeError {
        RuntimeError::OnChain(val)
    }
}

impl From<OnChainError> for EvalOnChainError {
    fn from(val: OnChainError) -> EvalOnChainError {
        EvalOnChainError::OnChain(val)
    }
}

impl From<OnChainError> for EvalError {
    fn from(val: OnChainError) -> EvalError {
        EvalError::OnChain(val)
    }
}

#[derive(Debug, Clone)]
pub enum NotSupportedError {
    /// The memory index is too large for the implementation of the VM to
    /// handle.
    MemoryIndexNotSupported,
}

impl From<NotSupportedError> for RuntimeError {
    fn from(val: NotSupportedError) -> RuntimeError {
        RuntimeError::NotSupported(val)
    }
}

impl From<NotSupportedError> for EvalError {
    fn from(val: NotSupportedError) -> EvalError {
        EvalError::NotSupported(val)
    }
}

#[derive(Debug, Clone)]
pub enum RuntimeError {
    /// On chain error.
    OnChain(OnChainError),
    /// Off chain error due to VM not supported.
    NotSupported(NotSupportedError),
}

impl From<RuntimeError> for EvalError {
    fn from(val: RuntimeError) -> EvalError {
        match val {
            RuntimeError::OnChain(err) =>
                EvalError::OnChain(err),
            RuntimeError::NotSupported(err) =>
                EvalError::NotSupported(err),
        }
    }
}

#[derive(Debug, Clone)]
pub enum EvalOnChainError {
    OnChain(OnChainError),
    Require(RequireError),
}

impl From<EvalOnChainError> for EvalError {
    fn from(val: EvalOnChainError) -> EvalError {
        match val {
            EvalOnChainError::OnChain(err) =>
                EvalError::OnChain(err),
            EvalOnChainError::Require(err) =>
                EvalError::Require(err),
        }
    }
}

#[derive(Debug, Clone)]
pub enum EvalError {
    OnChain(OnChainError),
    NotSupported(NotSupportedError),
    Require(RequireError),
}

#[derive(Debug, Clone)]
/// Errors stating that the VM requires additional information to
/// continue running.
pub enum RequireError {
    /// Requires the account at address for the VM to continue
    /// running, this should usually be dealt by
    /// `vm.commit_account(AccountCommitment::Full { .. })` or
    /// `vm.commit_account(AccountCommitment::Nonexist(..))`.
    Account(Address),
    /// Requires the account code at address for the VM to continue
    /// running, this should usually be dealt by
    /// `vm.commit_account(AccountCommitment::Code { .. })`.
    AccountCode(Address),
    /// Requires the current value of the storage for the VM to
    /// continue running, this should usually be dealt by
    /// `vm.commit_account(AccountCommitment::Storage { .. }`.
    AccountStorage(Address, U256),
    /// Requires the blockhash for the VM to continue running, this
    /// should usually be dealt by `vm.commit_blockhash(..)`.
    Blockhash(U256),
}

impl From<RequireError> for EvalError {
    fn from(val: RequireError) -> EvalError {
        EvalError::Require(val)
    }
}

impl From<RequireError> for EvalOnChainError {
    fn from(val: RequireError) -> EvalOnChainError {
        EvalOnChainError::Require(val)
    }
}

#[derive(Debug, Clone)]
/// Errors returned when committing a new information.
pub enum CommitError {
    /// The commitment is invalid.
    InvalidCommitment,
    /// The commitment has already been committed.
    AlreadyCommitted,
}
<|endoftext|>