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

use Result;

use chrono::Duration;
use serde_ini;

use std::io;
use std::path::PathBuf;

use serde_helpers::de;

const SYSTEM_SETTINGS_PATH: &str = "/etc/updatehub.conf";

#[cfg(not(test))]
const SERVER_URL: &str = "https://api.updatehub.io";

// When running inside a test environment we default to the mock
// server
#[cfg(test)]
use mockito;
#[cfg(test)]
const SERVER_URL: &str = mockito::SERVER_URL;

#[derive(Debug, Default, PartialEq, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Settings {
    pub firmware: Firmware,
    pub network: Network,
    pub polling: Polling,
    pub storage: Storage,
    pub update: Update,
}

impl Settings {
    /// Loads the settings from the filesystem. If
    /// `/etc/updatehub.conf` does not exists, it uses the default
    /// settings.
    pub fn load() -> Result<Self> {
        use std::fs::File;
        use std::io::Read;
        use std::path::Path;

        let path = Path::new(SYSTEM_SETTINGS_PATH);

        if path.exists() {
            info!(
                "Loading system settings from '{}'...",
                path.to_string_lossy()
            );

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;

            Ok(Settings::parse(&content)?)
        } else {
            debug!(
                "System settings file {} does not exists.",
                path.to_string_lossy()
            );
            info!("Using default system settings...");
            Ok(Settings::default())
        }
    }

    // This parses the configuration file, taking into account the
    // needed validations for all fields, and returns either `Self` or
    // `Err`.
    fn parse(content: &str) -> Result<Self> {
        let settings = serde_ini::from_str::<Settings>(content)?;

        if settings.polling.interval < Duration::seconds(60) {
            error!(
                "Invalid setting for polling interval. The interval cannot be less than 60 seconds"
            );
            return Err(SettingsError::InvalidInterval.into());
        }

        if !&settings.network.server_address.starts_with("http://")
            && !&settings.network.server_address.starts_with("https://")
        {
            error!("Invalid setting for server address. The server address must use the protocol prefix");
            return Err(SettingsError::InvalidServerAddress.into());
        }

        Ok(settings)
    }
}

#[derive(Debug, Fail)]
pub enum SettingsError {
    #[cause]
    #[fail(display = "IO error")]
    Io(io::Error),
    #[cause]
    #[fail(display = "Invalid INI fail")]
    Ini(serde_ini::de::Error),
    #[fail(display = "Invalid interval")]
    InvalidInterval,
    #[fail(display = "Invalid server address")]
    InvalidServerAddress,
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Polling {
    #[serde(deserialize_with = "de::duration_from_str")]
    pub interval: Duration,
    #[serde(deserialize_with = "de::bool_from_str")]
    pub enabled: bool,
}

impl Default for Polling {
    fn default() -> Self {
        Polling {
            interval: Duration::days(1),
            enabled: true,
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Storage {
    #[serde(deserialize_with = "de::bool_from_str")]
    pub read_only: bool,
    pub runtime_settings: String,
}

impl Default for Storage {
    fn default() -> Self {
        Storage {
            read_only: false,
            runtime_settings: "/var/lib/updatehub/runtime_settings.conf".into(),
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Update {
    pub download_dir: PathBuf,
    #[serde(rename = "SupportedInstallModes")]
    #[serde(deserialize_with = "de::vec_from_str")]
    pub install_modes: Vec<String>,
}

impl Default for Update {
    fn default() -> Self {
        Update {
            download_dir: "/tmp/updatehub".into(),
            install_modes: [
                "dry-run", "copy", "flash", "imxkobs", "raw", "tarball", "ubifs",
            ]
                .iter()
                .map(|i| i.to_string())
                .collect(),
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Network {
    pub server_address: String,
}

impl Default for Network {
    fn default() -> Self {
        Network {
            server_address: SERVER_URL.into(),
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Firmware {
    pub metadata_path: PathBuf,
}

impl Default for Firmware {
    fn default() -> Self {
        Firmware {
            metadata_path: "/usr/share/updatehub".into(),
        }
    }
}

#[test]
fn ok() {
    let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";

    let expected = Settings {
        polling: Polling {
            interval: Duration::seconds(60),
            enabled: false,
        },
        storage: Storage {
            read_only: true,
            runtime_settings: "/run/updatehub/state".into(),
        },
        update: Update {
            download_dir: "/tmp/download".into(),
            install_modes: ["mode1", "mode2"].iter().map(|i| i.to_string()).collect(),
        },
        network: Network {
            server_address: "http://localhost".into(),
        },
        firmware: Firmware {
            metadata_path: "/tmp/metadata".into(),
        },
    };

    assert_eq!(
        serde_ini::from_str::<Settings>(ini)
            .map_err(|e| println!("{}", e))
            .ok(),
        Some(expected)
    );
}

#[test]
fn invalid_polling_interval() {
    let ini = r"
[Polling]
Interval=59s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";
    assert!(Settings::parse(ini).is_err());
}

#[test]
fn invalid_network_server_address() {
    let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=localhost

[Firmware]
MetadataPath=/tmp/metadata
";
    assert!(Settings::parse(ini).is_err());
}

#[test]
fn default() {
    let settings = Settings::default();
    let expected = Settings {
        polling: Polling {
            interval: Duration::days(1),
            enabled: true,
        },
        storage: Storage {
            read_only: false,
            runtime_settings: "/var/lib/updatehub/runtime_settings.conf".into(),
        },
        update: Update {
            download_dir: "/tmp/updatehub".into(),
            install_modes: [
                "dry-run", "copy", "flash", "imxkobs", "raw", "tarball", "ubifs",
            ]
                .iter()
                .map(|i| i.to_string())
                .collect(),
        },
        network: Network {
            server_address: SERVER_URL.into(),
        },
        firmware: Firmware {
            metadata_path: "/usr/share/updatehub".into(),
        },
    };

    assert_eq!(Some(settings), Some(expected));
}
<commit_msg>settings: polling: Add documentation<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: MPL-2.0
//

use Result;

use chrono::Duration;
use serde_ini;

use std::io;
use std::path::PathBuf;

use serde_helpers::de;

const SYSTEM_SETTINGS_PATH: &str = "/etc/updatehub.conf";

#[cfg(not(test))]
const SERVER_URL: &str = "https://api.updatehub.io";

// When running inside a test environment we default to the mock
// server
#[cfg(test)]
use mockito;
#[cfg(test)]
const SERVER_URL: &str = mockito::SERVER_URL;

#[derive(Debug, Default, PartialEq, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Settings {
    pub firmware: Firmware,
    pub network: Network,
    pub polling: Polling,
    pub storage: Storage,
    pub update: Update,
}

impl Settings {
    /// Loads the settings from the filesystem. If
    /// `/etc/updatehub.conf` does not exists, it uses the default
    /// settings.
    pub fn load() -> Result<Self> {
        use std::fs::File;
        use std::io::Read;
        use std::path::Path;

        let path = Path::new(SYSTEM_SETTINGS_PATH);

        if path.exists() {
            info!(
                "Loading system settings from '{}'...",
                path.to_string_lossy()
            );

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;

            Ok(Settings::parse(&content)?)
        } else {
            debug!(
                "System settings file {} does not exists.",
                path.to_string_lossy()
            );
            info!("Using default system settings...");
            Ok(Settings::default())
        }
    }

    // This parses the configuration file, taking into account the
    // needed validations for all fields, and returns either `Self` or
    // `Err`.
    fn parse(content: &str) -> Result<Self> {
        let settings = serde_ini::from_str::<Settings>(content)?;

        if settings.polling.interval < Duration::seconds(60) {
            error!(
                "Invalid setting for polling interval. The interval cannot be less than 60 seconds"
            );
            return Err(SettingsError::InvalidInterval.into());
        }

        if !&settings.network.server_address.starts_with("http://")
            && !&settings.network.server_address.starts_with("https://")
        {
            error!("Invalid setting for server address. The server address must use the protocol prefix");
            return Err(SettingsError::InvalidServerAddress.into());
        }

        Ok(settings)
    }
}

#[derive(Debug, Fail)]
pub enum SettingsError {
    #[cause]
    #[fail(display = "IO error")]
    Io(io::Error),
    #[cause]
    #[fail(display = "Invalid INI fail")]
    Ini(serde_ini::de::Error),
    #[fail(display = "Invalid interval")]
    InvalidInterval,
    #[fail(display = "Invalid server address")]
    InvalidServerAddress,
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Polling {
    #[serde(deserialize_with = "de::duration_from_str")]
    /// Inverval to automatically poll the server for update. By
    /// default, it uses 1 day of interval.
    pub interval: Duration,
    #[serde(deserialize_with = "de::bool_from_str")]
    /// Defines if automatic polling is enabled or not. By default it
    /// is enabled.
    pub enabled: bool,
}

impl Default for Polling {
    fn default() -> Self {
        Polling {
            interval: Duration::days(1),
            enabled: true,
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Storage {
    #[serde(deserialize_with = "de::bool_from_str")]
    pub read_only: bool,
    pub runtime_settings: String,
}

impl Default for Storage {
    fn default() -> Self {
        Storage {
            read_only: false,
            runtime_settings: "/var/lib/updatehub/runtime_settings.conf".into(),
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Update {
    pub download_dir: PathBuf,
    #[serde(rename = "SupportedInstallModes")]
    #[serde(deserialize_with = "de::vec_from_str")]
    pub install_modes: Vec<String>,
}

impl Default for Update {
    fn default() -> Self {
        Update {
            download_dir: "/tmp/updatehub".into(),
            install_modes: [
                "dry-run", "copy", "flash", "imxkobs", "raw", "tarball", "ubifs",
            ]
                .iter()
                .map(|i| i.to_string())
                .collect(),
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Network {
    pub server_address: String,
}

impl Default for Network {
    fn default() -> Self {
        Network {
            server_address: SERVER_URL.into(),
        }
    }
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Firmware {
    pub metadata_path: PathBuf,
}

impl Default for Firmware {
    fn default() -> Self {
        Firmware {
            metadata_path: "/usr/share/updatehub".into(),
        }
    }
}

#[test]
fn ok() {
    let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";

    let expected = Settings {
        polling: Polling {
            interval: Duration::seconds(60),
            enabled: false,
        },
        storage: Storage {
            read_only: true,
            runtime_settings: "/run/updatehub/state".into(),
        },
        update: Update {
            download_dir: "/tmp/download".into(),
            install_modes: ["mode1", "mode2"].iter().map(|i| i.to_string()).collect(),
        },
        network: Network {
            server_address: "http://localhost".into(),
        },
        firmware: Firmware {
            metadata_path: "/tmp/metadata".into(),
        },
    };

    assert_eq!(
        serde_ini::from_str::<Settings>(ini)
            .map_err(|e| println!("{}", e))
            .ok(),
        Some(expected)
    );
}

#[test]
fn invalid_polling_interval() {
    let ini = r"
[Polling]
Interval=59s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";
    assert!(Settings::parse(ini).is_err());
}

#[test]
fn invalid_network_server_address() {
    let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=localhost

[Firmware]
MetadataPath=/tmp/metadata
";
    assert!(Settings::parse(ini).is_err());
}

#[test]
fn default() {
    let settings = Settings::default();
    let expected = Settings {
        polling: Polling {
            interval: Duration::days(1),
            enabled: true,
        },
        storage: Storage {
            read_only: false,
            runtime_settings: "/var/lib/updatehub/runtime_settings.conf".into(),
        },
        update: Update {
            download_dir: "/tmp/updatehub".into(),
            install_modes: [
                "dry-run", "copy", "flash", "imxkobs", "raw", "tarball", "ubifs",
            ]
                .iter()
                .map(|i| i.to_string())
                .collect(),
        },
        network: Network {
            server_address: SERVER_URL.into(),
        },
        firmware: Firmware {
            metadata_path: "/usr/share/updatehub".into(),
        },
    };

    assert_eq!(Some(settings), Some(expected));
}
<|endoftext|>


<commit_before>
use glfw;
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use piston::gl::Gl;
use graphics;
use graphics::*;
use Object = object::Object;

pub struct SnakeApp {
    settings: Settings,
    player_index: Option<uint>,
    // Contains the game objects.
    objects: Vec<Object>,
}

impl Game for SnakeApp {
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }

    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        for obj in self.objects.iter() {
            obj.render(c, gl);
        }
    }

    fn update(&mut self) {
        let dt = 0.1;
        for obj in self.objects.mut_iter() {
            obj.update(dt);
        }
    }

    fn load(&mut self) {
        self.objects.push(Object::new([0.0, 0.0]));
        self.player_index = Some(0);
    }

    fn key_press(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key pressed {}", key);

        match (key, self.player_index) {
            (glfw::KeyRight, Some(player_index)) => {
                self.objects.get_mut(player_index).move_right();
            },
            (glfw::KeyUp, Some(player_index)) => {
                self.objects.get_mut(player_index).move_up();
            },
            (glfw::KeyLeft, Some(player_index)) => {
                self.objects.get_mut(player_index).move_left();
            },
            (glfw::KeyDown, Some(player_index)) => {
                self.objects.get_mut(player_index).move_down();
            },
            _ => {},
        }
    }

    fn key_release(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key released {}", key);
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            settings: Settings::new(exit_on_esc, background_color),
            objects: Vec::new(),
            player_index: None,
        }
    }
}

<commit_msg>Using fixed time step<commit_after>
use glfw;
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use piston::gl::Gl;
use graphics;
use graphics::*;
use Object = object::Object;

pub struct SnakeApp {
    settings: Settings,
    player_index: Option<uint>,
    // Contains the game objects.
    objects: Vec<Object>,
}

impl Game for SnakeApp {
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }

    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        for obj in self.objects.iter() {
            obj.render(c, gl);
        }
    }

    fn update(&mut self, dt: f64) {
        for obj in self.objects.mut_iter() {
            obj.update(dt);
        }
    }

    fn load(&mut self) {
        self.objects.push(Object::new([0.0, 0.0]));
        self.player_index = Some(0);
    }

    fn key_press(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key pressed {}", key);

        match (key, self.player_index) {
            (glfw::KeyRight, Some(player_index)) => {
                self.objects.get_mut(player_index).move_right();
            },
            (glfw::KeyUp, Some(player_index)) => {
                self.objects.get_mut(player_index).move_up();
            },
            (glfw::KeyLeft, Some(player_index)) => {
                self.objects.get_mut(player_index).move_left();
            },
            (glfw::KeyDown, Some(player_index)) => {
                self.objects.get_mut(player_index).move_down();
            },
            _ => {},
        }
    }

    fn key_release(&mut self, key: glfw::Key) {
        // TEST
        // println!("Key released {}", key);
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            settings: Settings::new(exit_on_esc, background_color),
            objects: Vec::new(),
            player_index: None,
        }
    }
}

<|endoftext|>


<commit_before>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;
use std::mem;
use std::slice::Iter;

use Result;
/// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    /// convert self into a Sexp
    fn into_sexp(&self) -> Sexp;
}

impl Into<Sexp> for Vec<Sexp> {
    fn into(self: Vec<Sexp>) -> Sexp {
        Sexp::List(self)
    }
}

impl Into<Sexp> for String {
    fn into(self: String) -> Sexp {
        Sexp::String(self)
    }
}

impl<'a> From<&'a str> for Sexp {
    fn from(t: &str) -> Sexp {
        Sexp::String(t.into())
    }
}

impl<'a> From<&'a String> for Sexp {
    fn from(t: &String) -> Sexp {
        Sexp::String(t.clone())
    }
}

impl Into<Sexp> for i64 {
    fn into(self: i64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl Into<Sexp> for f64 {
    fn into(self: f64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl<'a> From<(&'a str, Sexp)> for Sexp {
    fn from(kv: (&str, Sexp)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(value);
        v.into()
    }
}

impl<'a, T: fmt::Display> From<(&'a str, &'a T)> for Sexp {
    fn from(kv: (&str, &T)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }
}

/// a symbolic-expression
/// Can be a string or a list or nothing
#[derive(Debug, Clone, PartialEq)]
pub enum Sexp {
    /// plain String symbolic-expression
    String(String),
    /// list symbolic-expression
    List(Vec<Sexp>),
    /// empty, trivial symbolic-expression
    Empty,
}

/// Atom iterator wrapper
pub struct IterAtom<'a> {
    i:Iter<'a,Sexp>,
}

// Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
// A string may not contain an actual newline or carriage return,
// but it may use an escape sequence to encode a // newline, such as \n.
// If a string has any of the following conditions, then it must be quoted
// with a leading and trailing double quote
// character, otherwise it is acceptable to not quote the string:
// 1. has one or more of the following 4 separator bytes: ASCII space,
// tab, '(', or ')'.
// 2. has one or more of the following bytes: '%', '{', or '}'.
// 3. has a length of zero bytes, and you need a place holder for the field,
//  then use "".
// 4. includes a byte of '-', and this byte is not in the first position of
// the string.
//

// Joost remark: kicad no longer seems to follow Rule 4.
// so we don't either

/// encode a string according to the guidelines given by Kicad
pub fn encode_string(s: &str) -> String {
    // fn rule_4(s:&str) -> bool {
    // s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    // }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') ||
       s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') ||
       s.is_empty()
    // || rule_4(s)
    {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {
    /// create an empty symbolic-expression
    #[deprecated(since="4.0.0", note="please use `Sexp::default()` instead")]
    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    /// create a String type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_string<T>(s: T) -> Sexp
        where T: fmt::Display
    {
        format!("{}", s).into()
    }

    /// create a list type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_list(v: Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    /// create an empty list type symbolic-expression
    pub fn start(name: &str) -> Sexp {
        let mut v = vec![];
        v.push(Sexp::String(name.into()));
        Sexp::List(v)
    }

    /// push an element in a list
    pub fn push<T: Into<Sexp>>(&mut self, element: T) {
        match *self {
            Sexp::List(ref mut v) => v.push(element.into()),
            _ => panic!("Only use push on lists!"),
        }
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, the remainder is filled in via the provided
    /// fill function
    pub fn new_named_list<F>(name: &str, fill: F) -> Sexp
        where F: Fn(&mut Vec<Sexp>)
    {
        let mut v = vec![];
        v.push(name.into());
        fill(&mut v);
        Sexp::List(v)
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_named<T>(name: &str, value: T) -> Sexp
        where T: fmt::Display
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, and the second is another symbolic-expression
    /// created via the IntoSexp trait
    #[deprecated(since="4.0.5", note="please use `.into()` on a tuple instead")]
    pub fn new_named_sexp<T>(name: &str, value: &T) -> Sexp
        where T: IntoSexp
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    /// if the expression is a list, take out the list and swap it with Empty
    pub fn take_list(&mut self) -> Result<Vec<Sexp>> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::List(v) => Ok(v),
            _ => Err(format!("Not a list: {}", e).into()),
        }
    }

    /// if the expression is a string, take it out and swap it with Empty
    pub fn take_string(&mut self) -> Result<String> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::String(s) => Ok(s),
            _ => Err(format!("Not a string: {}", e).into()),
        }
    }

    /// create a symbolic-expression via the IntoSexp trait
    pub fn from<T: IntoSexp>(t: &T) -> Sexp {
        t.into_sexp()
    }

    /// access the symbolic-expression as if it is a List
    pub fn list(&self) -> Result<&Vec<Sexp>> {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self).into()),
        }
    }

    /// access the symbolic-expression as if it is a String
    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self).into()),
        }
    }

    /// is this expression a string
    pub fn is_string(&self) -> bool {
        match *self {
            Sexp::String(_) => true,
            _ => false,
        }
    }

    /// is this expression a list
    pub fn is_list(&self) -> bool {
        match *self {
            Sexp::List(_) => true,
            _ => false,
        }
    }

    /// access the symbolic-expression as if it is a String
    /// that is a f64
    pub fn f(&self) -> Result<f64> {
        let s = self.string()?;
        let f = f64::from_str(s)?;
        Ok(f)
    }

    /// access the symbolic-expression as if it is a String
    /// that is an i64
    pub fn i(&self) -> Result<i64> {
        let s = self.string()?;
        let i = i64::from_str(s)?;
        Ok(i)
    }

    /// access the symbolic-expression as if it is a List
    /// assuming the first element is a String and return that
    pub fn list_name(&self) -> Result<&String> {
        let l = self.list()?;
        let l = &l[..];
        let a = l[0].string()?;
        Ok(a)
    }

    /// access the symbolic-expression as if it is a named List
    /// where the name is provided and returns the remaining elements
    /// after the name as a slice
    pub fn slice_atom(&self, s: &str) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(&v[1..])
    }

    /// access the symbolic-expression as if it is a named List
    /// iterator experiment
    pub fn iter_atom(&self, s:&str) -> Result<IterAtom> {
        let v = self.list()?;
        let mut i = v.iter();
        let st = match i.next() {
            None => return Err(format!("missing first element {} in list {}", s, self).into()),
            Some(e) => e.string()?,

        };
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(IterAtom { i:i })
    }

    /// access the symbolic-expression as if it is a named List
    /// with two elements where the name is provided and returns
    /// the next element in the list
    pub fn named_value(&self, s: &str) -> Result<&Sexp> {
        let v = self.list()?;
        if v.len() != 2 {
            return Err(format!("list {} is not a named_value", s).into());
        }
        let l = self.slice_atom(s)?;
        Ok(&l[0])
    }

    /// as named_value but converted to i64
    pub fn named_value_i(&self, s: &str) -> Result<i64> {
        self.named_value(s)?.i()
    }

    /// as named_value but converted to f64
    pub fn named_value_f(&self, s: &str) -> Result<f64> {
        self.named_value(s)?.f()
    }

    /// as named_value but converted to String
    pub fn named_value_string(&self, s: &str) -> Result<&String> {
        self.named_value(s)?.string()
    }

    /// get the symbolic-expression as a list which starts
    /// with a string that indicates the name and has num more
    /// elements, returns those elements
    pub fn slice_atom_num(&self, s: &str, num: usize) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st).into());
        };
        if v.len() != (num + 1) {
            return Err(format!("list ({}) doesn't have {} elements but {}",
                               s,
                               num,
                               v.len() - 1)
                .into());
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => write!(f, "{}", encode_string(s)),
            Sexp::List(ref v) => {
                write!(f, "(")?;
                let l = v.len();
                for (i, x) in v.iter().enumerate() {
                    if i < l - 1 {
                        write!(f, "{} ", x)?;
                    } else {
                        write!(f, "{}", x)?;
                    }
                }
                write!(f, ")")
            }
            Sexp::Empty => Ok(()),
        }
    }
}

impl Default for Sexp {
    fn default() -> Sexp {
        Sexp::Empty
    }
}

impl<'a> IterAtom<'a> {

    fn expect<T,F>(&mut self, sname:&str, name:&str, get:F) -> Result<T>
        where F:Fn(&Sexp) -> Result<T>
    {
        let x = match self.i.next() {
            Some(x) => get(x)?,
            None => return Err(format!("missing {} field in {}",name, sname).into()),
        };
        Ok(x)
    }

    fn optional<T,F>(&mut self, or:T, get:F) -> Result<T>
        where F:Fn(&Sexp) -> Result<T>
    {
        let x = match self.i.next() {
            Some(x) => get(x)?,
            None => or,
        };
        Ok(x)
    }

    /// expect an integer while iterating a `Sexp` list
    pub fn expect_i(&mut self, sname:&str, name:&str) -> Result<i64> {
        self.expect(sname, name, |x| x.i())
    }

    /// expect a float while iterating a `Sexp` list
    pub fn expect_f(&mut self, sname:&str, name:&str) -> Result<f64> {
        self.expect(sname, name, |x| x.f())
    }

    /// expect a String while iterating a `Sexp` list
    pub fn expect_s(&mut self, sname:&str, name:&str) -> Result<String> {
        self.expect(sname, name, |x| x.string().map(|y| y.clone()))
    }

    /// optional integer while iterating a `Sexp` list
    pub fn optional_i(&mut self, or:i64) -> Result<i64> {
        self.optional(or, |x| x.i())
    }

    /// optional float while iterating a `Sexp` list
    pub fn optional_f(&mut self, or:f64) -> Result<f64> {
        self.optional(or, |x| x.f())
    }

    /// optional String while iterating a `Sexp` list
    pub fn optional_s(&mut self, or:String) -> Result<String> {
        self.optional(or, |x| x.string().map(|y| y.clone()))
    }
}
<commit_msg>shorter names<commit_after>// (c) 2016-2017 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;
use std::mem;
use std::slice::Iter;

use Result;
/// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    /// convert self into a Sexp
    fn into_sexp(&self) -> Sexp;
}

impl Into<Sexp> for Vec<Sexp> {
    fn into(self: Vec<Sexp>) -> Sexp {
        Sexp::List(self)
    }
}

impl Into<Sexp> for String {
    fn into(self: String) -> Sexp {
        Sexp::String(self)
    }
}

impl<'a> From<&'a str> for Sexp {
    fn from(t: &str) -> Sexp {
        Sexp::String(t.into())
    }
}

impl<'a> From<&'a String> for Sexp {
    fn from(t: &String) -> Sexp {
        Sexp::String(t.clone())
    }
}

impl Into<Sexp> for i64 {
    fn into(self: i64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl Into<Sexp> for f64 {
    fn into(self: f64) -> Sexp {
        Sexp::String(format!("{}", self))
    }
}

impl<'a> From<(&'a str, Sexp)> for Sexp {
    fn from(kv: (&str, Sexp)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(value);
        v.into()
    }
}

impl<'a, T: fmt::Display> From<(&'a str, &'a T)> for Sexp {
    fn from(kv: (&str, &T)) -> Sexp {
        let (name, value) = kv;
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }
}

/// a symbolic-expression
/// Can be a string or a list or nothing
#[derive(Debug, Clone, PartialEq)]
pub enum Sexp {
    /// plain String symbolic-expression
    String(String),
    /// list symbolic-expression
    List(Vec<Sexp>),
    /// empty, trivial symbolic-expression
    Empty,
}

/// Atom iterator wrapper
pub struct IterAtom<'a> {
    iter:Iter<'a,Sexp>,
}

// Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
// A string may not contain an actual newline or carriage return,
// but it may use an escape sequence to encode a // newline, such as \n.
// If a string has any of the following conditions, then it must be quoted
// with a leading and trailing double quote
// character, otherwise it is acceptable to not quote the string:
// 1. has one or more of the following 4 separator bytes: ASCII space,
// tab, '(', or ')'.
// 2. has one or more of the following bytes: '%', '{', or '}'.
// 3. has a length of zero bytes, and you need a place holder for the field,
//  then use "".
// 4. includes a byte of '-', and this byte is not in the first position of
// the string.
//

// Joost remark: kicad no longer seems to follow Rule 4.
// so we don't either

/// encode a string according to the guidelines given by Kicad
pub fn encode_string(s: &str) -> String {
    // fn rule_4(s:&str) -> bool {
    // s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    // }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') ||
       s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') ||
       s.is_empty()
    // || rule_4(s)
    {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {
    /// create an empty symbolic-expression
    #[deprecated(since="4.0.0", note="please use `Sexp::default()` instead")]
    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    /// create a String type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_string<T>(s: T) -> Sexp
        where T: fmt::Display
    {
        format!("{}", s).into()
    }

    /// create a list type symbolic-expression
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_list(v: Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    /// create an empty list type symbolic-expression
    pub fn start(name: &str) -> Sexp {
        let mut v = vec![];
        v.push(Sexp::String(name.into()));
        Sexp::List(v)
    }

    /// push an element in a list
    pub fn push<T: Into<Sexp>>(&mut self, element: T) {
        match *self {
            Sexp::List(ref mut v) => v.push(element.into()),
            _ => panic!("Only use push on lists!"),
        }
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, the remainder is filled in via the provided
    /// fill function
    pub fn new_named_list<F>(name: &str, fill: F) -> Sexp
        where F: Fn(&mut Vec<Sexp>)
    {
        let mut v = vec![];
        v.push(name.into());
        fill(&mut v);
        Sexp::List(v)
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name
    #[deprecated(since="4.0.3", note="please use `.into()` instead")]
    pub fn new_named<T>(name: &str, value: T) -> Sexp
        where T: fmt::Display
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(format!("{}", value).into());
        v.into()
    }

    /// create a list type symbolic-expression where
    /// the first element of the list is a string that indicates
    /// the name, and the second is another symbolic-expression
    /// created via the IntoSexp trait
    #[deprecated(since="4.0.5", note="please use `.into()` on a tuple instead")]
    pub fn new_named_sexp<T>(name: &str, value: &T) -> Sexp
        where T: IntoSexp
    {
        let mut v = vec![];
        v.push(name.into());
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    /// if the expression is a list, take out the list and swap it with Empty
    pub fn take_list(&mut self) -> Result<Vec<Sexp>> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::List(v) => Ok(v),
            _ => Err(format!("Not a list: {}", e).into()),
        }
    }

    /// if the expression is a string, take it out and swap it with Empty
    pub fn take_string(&mut self) -> Result<String> {
        let mut e = Sexp::Empty;
        mem::swap(&mut e, self);
        match e {
            Sexp::String(s) => Ok(s),
            _ => Err(format!("Not a string: {}", e).into()),
        }
    }

    /// create a symbolic-expression via the IntoSexp trait
    pub fn from<T: IntoSexp>(t: &T) -> Sexp {
        t.into_sexp()
    }

    /// access the symbolic-expression as if it is a List
    pub fn list(&self) -> Result<&Vec<Sexp>> {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self).into()),
        }
    }

    /// access the symbolic-expression as if it is a String
    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self).into()),
        }
    }

    /// is this expression a string
    pub fn is_string(&self) -> bool {
        match *self {
            Sexp::String(_) => true,
            _ => false,
        }
    }

    /// is this expression a list
    pub fn is_list(&self) -> bool {
        match *self {
            Sexp::List(_) => true,
            _ => false,
        }
    }

    /// access the symbolic-expression as if it is a String
    /// that is a f64
    pub fn f(&self) -> Result<f64> {
        let s = self.string()?;
        let f = f64::from_str(s)?;
        Ok(f)
    }

    /// access the symbolic-expression as if it is a String
    /// that is an i64
    pub fn i(&self) -> Result<i64> {
        let s = self.string()?;
        let i = i64::from_str(s)?;
        Ok(i)
    }

    /// access the symbolic-expression as if it is a List
    /// assuming the first element is a String and return that
    pub fn list_name(&self) -> Result<&String> {
        let l = self.list()?;
        let l = &l[..];
        let a = l[0].string()?;
        Ok(a)
    }

    /// access the symbolic-expression as if it is a named List
    /// where the name is provided and returns the remaining elements
    /// after the name as a slice
    pub fn slice_atom(&self, s: &str) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(&v[1..])
    }

    /// access the symbolic-expression as if it is a named List
    /// iterator experiment
    pub fn iter_atom(&self, s:&str) -> Result<IterAtom> {
        let v = self.list()?;
        let mut i = v.iter();
        let st = match i.next() {
            None => return Err(format!("missing first element {} in list {}", s, self).into()),
            Some(e) => e.string()?,

        };
        if st != s {
            return Err(format!("list {} doesn't start with {}, but with {}", self, s, st).into());
        };
        Ok(IterAtom { iter:i })
    }

    /// access the symbolic-expression as if it is a named List
    /// with two elements where the name is provided and returns
    /// the next element in the list
    pub fn named_value(&self, s: &str) -> Result<&Sexp> {
        let v = self.list()?;
        if v.len() != 2 {
            return Err(format!("list {} is not a named_value", s).into());
        }
        let l = self.slice_atom(s)?;
        Ok(&l[0])
    }

    /// as named_value but converted to i64
    pub fn named_value_i(&self, s: &str) -> Result<i64> {
        self.named_value(s)?.i()
    }

    /// as named_value but converted to f64
    pub fn named_value_f(&self, s: &str) -> Result<f64> {
        self.named_value(s)?.f()
    }

    /// as named_value but converted to String
    pub fn named_value_string(&self, s: &str) -> Result<&String> {
        self.named_value(s)?.string()
    }

    /// get the symbolic-expression as a list which starts
    /// with a string that indicates the name and has num more
    /// elements, returns those elements
    pub fn slice_atom_num(&self, s: &str, num: usize) -> Result<&[Sexp]> {
        let v = self.list()?;
        let v2 = &v[..];
        let st = v2[0].string()?;
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st).into());
        };
        if v.len() != (num + 1) {
            return Err(format!("list ({}) doesn't have {} elements but {}",
                               s,
                               num,
                               v.len() - 1)
                .into());
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => write!(f, "{}", encode_string(s)),
            Sexp::List(ref v) => {
                write!(f, "(")?;
                let l = v.len();
                for (i, x) in v.iter().enumerate() {
                    if i < l - 1 {
                        write!(f, "{} ", x)?;
                    } else {
                        write!(f, "{}", x)?;
                    }
                }
                write!(f, ")")
            }
            Sexp::Empty => Ok(()),
        }
    }
}

impl Default for Sexp {
    fn default() -> Sexp {
        Sexp::Empty
    }
}

impl<'a> IterAtom<'a> {

    fn expect<T,F>(&mut self, sname:&str, name:&str, get:F) -> Result<T>
        where F:Fn(&Sexp) -> Result<T>
    {
        let x = match self.iter.next() {
            Some(x) => get(x)?,
            None => return Err(format!("missing {} field in {}",name, sname).into()),
        };
        Ok(x)
    }

    fn optional<T,F>(&mut self, or:T, get:F) -> Result<T>
        where F:Fn(&Sexp) -> Result<T>
    {
        let x = match self.iter.next() {
            Some(x) => get(x)?,
            None => or,
        };
        Ok(x)
    }

    /// expect an integer while iterating a `Sexp` list
    pub fn i(&mut self, sname:&str, name:&str) -> Result<i64> {
        self.expect(sname, name, |x| x.i())
    }

    /// expect a float while iterating a `Sexp` list
    pub fn f(&mut self, sname:&str, name:&str) -> Result<f64> {
        self.expect(sname, name, |x| x.f())
    }

    /// expect a String while iterating a `Sexp` list
    pub fn s(&mut self, sname:&str, name:&str) -> Result<String> {
        self.expect(sname, name, |x| x.string().map(|y| y.clone()))
    }

    /// optional integer while iterating a `Sexp` list
    pub fn opt_i(&mut self, or:i64) -> Result<i64> {
        self.optional(or, |x| x.i())
    }

    /// optional float while iterating a `Sexp` list
    pub fn opt_f(&mut self, or:f64) -> Result<f64> {
        self.optional(or, |x| x.f())
    }

    /// optional String while iterating a `Sexp` list
    pub fn opt_s(&mut self, or:String) -> Result<String> {
        self.optional(or, |x| x.string().map(|y| y.clone()))
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::net::SocketAddr;
use std::collections::HashMap;
use rand::random;
use mio::net::TcpStream;

use network::{AppId,Backend,ConnectionError};

pub struct BackendMap {
  pub instances:    HashMap<AppId, BackendList>,
  pub max_failures: usize,
}

impl BackendMap {
  pub fn new() -> BackendMap {
    BackendMap {
      instances:    HashMap::new(),
      max_failures: 3,
    }
  }

  pub fn add_instance(&mut self, app_id: &str, instance_address: &SocketAddr) {
    self.instances.entry(app_id.to_string()).or_insert(BackendList::new()).add_instance(instance_address);
  }

  pub fn remove_instance(&mut self, app_id: &str, instance_address: &SocketAddr) {
    if let Some(instances) = self.instances.get_mut(app_id) {
      instances.remove_instance(instance_address);
    } else {
      error!("Instance was already removed");
    }
  }

  pub fn close_backend_connection(&mut self, app_id: &str, addr: &SocketAddr) {
    if let Some(app_instances) = self.instances.get_mut(app_id) {
      if let Some(ref mut backend) = app_instances.find_instance(addr) {
        (*backend.borrow_mut()).dec_connections();
      }
    }
  }

  pub fn backend_from_app_id(&mut self, app_id: &str) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    if let Some(ref mut app_instances) = self.instances.get_mut(app_id) {
      if app_instances.instances.len() == 0 {
        return Err(ConnectionError::NoBackendAvailable);
      }

      for _ in 0..self.max_failures {
        if let Some(ref mut b) = app_instances.next_available_instance() {
          let ref mut backend = *b.borrow_mut();
          info!("Connecting {} -> {:?}", app_id, (backend.address, backend.active_connections, backend.failures));
          let conn = backend.try_connect();
          if backend.failures >= max_failures_per_backend {
            error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
          }

          return conn.map(|c| (b.clone(), c));
        } else {
          error!("no more available backends for app {}", app_id);
          return Err(ConnectionError::NoBackendAvailable);
        }
      }
      Err(ConnectionError::NoBackendAvailable)
    } else {
      Err(ConnectionError::NoBackendAvailable)
    }
  }

  pub fn backend_from_sticky_session(&mut self, app_id: &str, sticky_session: u32) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    let sticky_conn: Option<Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError>> = self.instances
      .get_mut(app_id)
      .and_then(|app_instances| app_instances.find_sticky(sticky_session))
      .map(|b| {
        let ref mut backend = *b.borrow_mut();
        let conn = backend.try_connect();
        info!("Connecting {} -> {:?} using session {}", app_id, (backend.address, backend.active_connections, backend.failures), sticky_session);
        if backend.failures >= max_failures_per_backend {
          error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
        }

        conn.map(|c| (b.clone(), c))
    });

    if let Some(res) = sticky_conn {
      return res;
    } else {
      debug!("Couldn't find a backend corresponding to sticky_session {} for app {}", sticky_session, app_id);
      return self.backend_from_app_id(app_id);
    }
  }
}

const max_failures_per_backend: usize = 10;

pub struct BackendList {
  pub instances: Vec<Rc<RefCell<Backend>>>,
  pub next_id:   u32,
}

impl BackendList {
  pub fn new() -> BackendList {
    BackendList {
      instances: Vec::new(),
      next_id:   0,
    }
  }

  pub fn add_instance(&mut self, instance_address: &SocketAddr) {
    if self.instances.iter().find(|b| &(*b.borrow()).address == instance_address).is_none() {
      let backend = Rc::new(RefCell::new(Backend::new(*instance_address, self.next_id)));
      self.instances.push(backend);
      self.next_id += 1;
    }
  }

  pub fn remove_instance(&mut self, instance_address: &SocketAddr) {
    self.instances.retain(|backend| &(*backend.borrow()).address != instance_address);
  }

  pub fn find_instance(&mut self, instance_address: &SocketAddr) -> Option<&mut Rc<RefCell<Backend>>> {
    self.instances.iter_mut().find(|backend| &(*backend.borrow()).address == instance_address)
  }

  pub fn find_sticky(&mut self, sticky_session: u32) -> Option<&mut Rc<RefCell<Backend>>> {
    self.instances.iter_mut()
      .find(|b| b.borrow().id == sticky_session )
      .and_then(|b| {
        if b.borrow().can_open(max_failures_per_backend) {
          Some(b)
        } else {
          None
        }
      })
  }

  pub fn available_instances(&mut self) -> Vec<&mut Rc<RefCell<Backend>>> {
    self.instances.iter_mut()
      .filter(|backend| (*backend.borrow()).can_open(max_failures_per_backend))
      .collect()
  }

  pub fn next_available_instance(&mut self) -> Option<&mut Rc<RefCell<Backend>>> {
    let mut instances:Vec<&mut Rc<RefCell<Backend>>> = self.available_instances();
    if instances.is_empty() {
      return None;
    }

    let rnd = random::<usize>();
    let idx = rnd % instances.len();

    Some(instances.remove(idx))
  }
}
<commit_msg>Add RetryPolicy and ExponentialBackoffPolicy<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::net::SocketAddr;
use std::collections::HashMap;
use rand::random;
use mio::net::TcpStream;

use std::{cmp, thread, time};

use network::{AppId,Backend,ConnectionError};

pub struct BackendMap {
  pub instances:    HashMap<AppId, BackendList>,
  pub retry_policy: ExponentialBackoffPolicy,
  pub max_failures: usize,
}

impl BackendMap {
  pub fn new() -> BackendMap {
    BackendMap {
      instances:    HashMap::new(),
      retry_policy: ExponentialBackoffPolicy::new(MAX_FAILURES_PER_BACKEND),
      max_failures: 3,
    }
  }

  pub fn add_instance(&mut self, app_id: &str, instance_address: &SocketAddr) {
    self.instances.entry(app_id.to_string()).or_insert(BackendList::new()).add_instance(instance_address);
  }

  pub fn remove_instance(&mut self, app_id: &str, instance_address: &SocketAddr) {
    if let Some(instances) = self.instances.get_mut(app_id) {
      instances.remove_instance(instance_address);
    } else {
      error!("Instance was already removed");
    }
  }

  pub fn close_backend_connection(&mut self, app_id: &str, addr: &SocketAddr) {
    if let Some(app_instances) = self.instances.get_mut(app_id) {
      if let Some(ref mut backend) = app_instances.find_instance(addr) {
        (*backend.borrow_mut()).dec_connections();
      }
    }
  }

  pub fn backend_from_app_id(&mut self, app_id: &str) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    if let Some(ref mut app_instances) = self.instances.get_mut(app_id) {
      if app_instances.instances.len() == 0 {
        return Err(ConnectionError::NoBackendAvailable);
      }

      let mut retry_policy: &mut ExponentialBackoffPolicy = &mut self.retry_policy;
      retry_policy.try(|| {
        if let Some(ref mut b) = app_instances.next_available_instance() {
          let ref mut backend = *b.borrow_mut();

          info!("Connecting {} -> {:?}", app_id, (backend.address, backend.active_connections, backend.failures));

          let conn = backend.try_connect();
          if backend.failures >= MAX_FAILURES_PER_BACKEND {
            error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
          }

          return conn.map(|c| (b.clone(), c));
        }

        error!("no more available backends for app {}", app_id);
        Err(ConnectionError::NoBackendAvailable)
      })
    } else {
      Err(ConnectionError::NoBackendAvailable)
    }
  }

  pub fn backend_from_sticky_session(&mut self, app_id: &str, sticky_session: u32) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    let sticky_conn: Option<Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError>>;
    {
      let retry_policy: &mut ExponentialBackoffPolicy = &mut self.retry_policy;
      sticky_conn = self.instances
        .get_mut(app_id)
        .and_then(|app_instances| app_instances.find_sticky(sticky_session))
        .map(|b| {
          retry_policy.try(|| {
            let ref mut backend = *b.borrow_mut();
            let conn = backend.try_connect();
            info!("Connecting {} -> {:?} using session {}", app_id, (backend.address, backend.active_connections, backend.failures), sticky_session);
            if backend.failures >= MAX_FAILURES_PER_BACKEND {
              error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
            }

            conn.map(|c| (b.clone(), c))
          })
        });
    }

    if let Some(res) = sticky_conn {
      return res;
    } else {
      debug!("Couldn't find a backend corresponding to sticky_session {} for app {}", sticky_session, app_id);
      return self.backend_from_app_id(app_id);
    }
  }
}

const MAX_FAILURES_PER_BACKEND: usize = 10;

pub trait RetryPolicy {
  fn max_tries(&self) -> usize;
  fn current_tries(&self) -> usize;
  fn try<T, F: FnMut() -> Result<T, ConnectionError>>(&mut self, action: F) -> Result<T, ConnectionError>;

  fn can_try(&self) -> bool {
    self.current_tries() <= self.max_tries()
  }
}

#[derive(Debug)]
pub struct ExponentialBackoffPolicy {
  max_tries: usize,
  current_tries: usize
}

impl ExponentialBackoffPolicy {
  pub fn new(max_tries: usize) -> Self {
    ExponentialBackoffPolicy {
      max_tries: max_tries,
      current_tries: 0
    }
  }
}

impl RetryPolicy for ExponentialBackoffPolicy {
  fn max_tries(&self) -> usize {
    self.max_tries
  }

  fn current_tries(&self) -> usize {
    self.current_tries
  }

  fn try<T, F: FnMut() -> Result<T, ConnectionError>>(&mut self, mut action: F) -> Result<T, ConnectionError> {
    if self.can_try() {
      if let Ok(result) = action() {
        self.current_tries = 0;

        return Ok(result)
      } else {
        let millis = cmp::max(1, 1 << self.current_tries) * 1000;
        let sleep_duration = time::Duration::from_millis(millis);
        thread::sleep(sleep_duration);

        self.current_tries += 1;
        return self.try(action);
      }
    } else {
        return Err(ConnectionError::NoBackendAvailable);
    }
  }
}

pub struct BackendList {
  pub instances: Vec<Rc<RefCell<Backend>>>,
  pub next_id:   u32,
}

impl BackendList {
  pub fn new() -> BackendList {
    BackendList {
      instances: Vec::new(),
      next_id:   0,
    }
  }

  pub fn add_instance(&mut self, instance_address: &SocketAddr) {
    if self.instances.iter().find(|b| &(*b.borrow()).address == instance_address).is_none() {
      let backend = Rc::new(RefCell::new(Backend::new(*instance_address, self.next_id)));
      self.instances.push(backend);
      self.next_id += 1;
    }
  }

  pub fn remove_instance(&mut self, instance_address: &SocketAddr) {
    self.instances.retain(|backend| &(*backend.borrow()).address != instance_address);
  }

  pub fn find_instance(&mut self, instance_address: &SocketAddr) -> Option<&mut Rc<RefCell<Backend>>> {
    self.instances.iter_mut().find(|backend| &(*backend.borrow()).address == instance_address)
  }

  pub fn find_sticky(&mut self, sticky_session: u32) -> Option<&mut Rc<RefCell<Backend>>> {
    self.instances.iter_mut()
      .find(|b| b.borrow().id == sticky_session )
      .and_then(|b| {
        if b.borrow().can_open(MAX_FAILURES_PER_BACKEND) {
          Some(b)
        } else {
          None
        }
      })
  }

  pub fn available_instances(&mut self) -> Vec<&mut Rc<RefCell<Backend>>> {
    self.instances.iter_mut()
      .filter(|backend| (*backend.borrow()).can_open(MAX_FAILURES_PER_BACKEND))
      .collect()
  }

  pub fn next_available_instance(&mut self) -> Option<&mut Rc<RefCell<Backend>>> {
    let mut instances:Vec<&mut Rc<RefCell<Backend>>> = self.available_instances();
    if instances.is_empty() {
      return None;
    }

    let rnd = random::<usize>();
    let idx = rnd % instances.len();

    Some(instances.remove(idx))
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use super::atom::Atom;
use super::parser;
use super::token::{Token, Tokenizer, CurlyAroundTokenizer};
use std::collections::BTreeMap;

#[derive(Debug, PartialEq, Clone)]
pub enum Sexp {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Sexp>),

    // [ ... ]
    Array(Vec<Sexp>),

    // { key val ... }
    Map(Vec<(Sexp, Sexp)>),
}

impl Sexp {
    /// Converts a Sexp::Map into a BTreeMap<String, Sexp> if possible.
    pub fn into_map(self) -> Result<BTreeMap<String, Sexp>, &'static str> {
        match self {
            Sexp::Map(pairs) => {
                let mut map = BTreeMap::new();
                for (key, val) in pairs {
                    match key {
                        Sexp::Atom(Atom::Str(s)) => {
                            if map.insert(s, val).is_some() {
                                return Err("duplicate key");
                            }
                        }
                        _ => return Err("key has to be a string"),
                    }
                }
                return Ok(map);
            }
            _ => Err("expr is not a Sexp::Map"),
        }
    }

    pub fn get_uint(&self) -> Option<u64> {
        match self {
            &Sexp::Atom(Atom::UInt(u)) => Some(u),
            _ => None,
        }
    }

    pub fn get_int(&self) -> Option<i64> {
        match self {
            &Sexp::Atom(Atom::SInt(s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_float(&self) -> Option<f64> {
        match self {
            &Sexp::Atom(Atom::Float(f)) => Some(f),
            _ => None,
        }
    }

    pub fn get_str(&self) -> Option<&str> {
        match self {
            &Sexp::Atom(Atom::Str(ref s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_vec<'a, F, R>(&'a self, f: F) -> Option<Vec<R>>
        where F: Fn(&'a Sexp) -> Option<R>
    {
        match self {
            &Sexp::Array(ref ary) => {
                let mut a = Vec::new();
                for elm in ary.iter() {
                    if let Some(u) = f(elm) {
                        a.push(u);
                    } else {
                        return None;
                    }
                }
                Some(a)
            }
            _ => None,
        }
    }

    pub fn get_uint_vec(&self) -> Option<Vec<u64>> {
        self.get_vec(|elm| elm.get_uint())
    }

    pub fn parse_iter<'a, I>(mut iter: I) -> Result<Sexp, ()>
        where I: Iterator<Item = Token<'a>>
    {
        if let Ok(expr) = parser::parse_sexp(&mut iter) {
            if parser::at_end(&mut iter) {
                return Ok(expr);
            }
        }
        Err(())
    }

    pub fn parse(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(Tokenizer::new(s, true))
    }

    pub fn parse_toplevel(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(CurlyAroundTokenizer::new(Tokenizer::new(s, true)))
    }
}

impl<T> From<T> for Sexp where T: Into<Atom>
{
    fn from(t: T) -> Sexp {
        Sexp::Atom(t.into())
    }
}

impl From<()> for Sexp {
    fn from(_e: ()) -> Sexp {
        Sexp::Tuple(vec![])
    }
}

impl<A> From<(A,)> for Sexp where A: Into<Sexp>
{
    fn from(e: (A,)) -> Sexp {
        Sexp::Tuple(vec![e.0.into()])
    }
}

impl<A, B> From<(A, B)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>
{
    fn from(e: (A, B)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into()])
    }
}

impl<A, B, C> From<(A, B, C)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>
{
    fn from(e: (A, B, C)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into()])
    }
}

impl<A, B, C, D> From<(A, B, C, D)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>,
          D: Into<Sexp>
{
    fn from(e: (A, B, C, D)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into(), e.3.into()])
    }
}

impl<A> From<Vec<A>> for Sexp where A: Into<Sexp>
{
    fn from(arr: Vec<A>) -> Sexp {
        Sexp::Array(arr.into_iter().map(|e| e.into()).collect())
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Sexp::Atom(ref a) => write!(f, "{}", a),
            Sexp::Tuple(ref t) => {
                try!(write!(f, "("));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, ")")
            }
            Sexp::Array(ref t) => {
                try!(write!(f, "["));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, "]")
            }
            Sexp::Map(ref t) => {
                try!(write!(f, "{}", "{"));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{} {}", space, expr.0, expr.1));
                }
                write!(f, "{}", "}")
            }

        }
    }
}

#[test]
fn test_display() {
    assert_eq!("12345", &format!("{}", Sexp::Atom(Atom::UInt(12345))));
    assert_eq!("1.0", &format!("{}", Sexp::Atom(Atom::Float(1.0))));

    assert_eq!("(12345)",
               &format!("{}", Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345))])));
    assert_eq!("(12345 abc)",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Atom(Atom::Str("abc".to_string()))])));
    assert_eq!("(12345 (abc))",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Tuple(vec![
                                         Sexp::Atom(Atom::Str("abc".to_string()))
                                         ])])));

}

#[test]
fn test_from() {
    assert_eq!(Sexp::Atom(Atom::UInt(123)), Sexp::from(123u64));
    assert_eq!(Sexp::Atom(Atom::SInt(123)), Sexp::from(123i64));
    assert_eq!(Sexp::Atom(Atom::Str("test".to_string())),
               Sexp::from("test"));
    assert_eq!(Sexp::Atom(Atom::Float(123.45)), Sexp::from(123.45));
    assert_eq!(Sexp::Tuple(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from((123.45,)));
    assert_eq!(Sexp::Array(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from(vec![123.45]));

}

#[test]
fn test_parse() {
    assert_eq!(Ok(Sexp::from(("abc", 123u64, ("-", 123.43, 11.0)))),
               Sexp::parse("(abc 123 (- 123.43 11.0))"));
}

#[test]
fn test_parse_toplevel() {
    assert_eq!(Sexp::parse("{a 1 b 2}"), Sexp::parse_toplevel("a 1 b 2"));
}

#[test]
fn test_map() {
    let map = Sexp::parse("{a 1 b 2}").unwrap().into_map().unwrap();
    assert_eq!(true, map.contains_key("a"));
    assert_eq!(true, map.contains_key("b"));
    assert_eq!(false, map.contains_key("c"));

    assert_eq!(Err("duplicate key"),
               Sexp::parse("{a 1 b 2 a 1}").unwrap().into_map());
    assert_eq!(Err("key has to be a string"),
               Sexp::parse("{1 1 b 2 a 1}").unwrap().into_map());

}
<commit_msg>Implement basic prettyprint<commit_after>use std::fmt;
use super::atom::Atom;
use super::parser;
use super::token::{Token, Tokenizer, CurlyAroundTokenizer};
use std::collections::BTreeMap;

#[derive(Debug, PartialEq, Clone)]
pub enum Sexp {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Sexp>),

    // [ ... ]
    Array(Vec<Sexp>),

    // { key val ... }
    Map(Vec<(Sexp, Sexp)>),
}

impl Sexp {
    /// Converts a Sexp::Map into a BTreeMap<String, Sexp> if possible.
    pub fn into_map(self) -> Result<BTreeMap<String, Sexp>, &'static str> {
        match self {
            Sexp::Map(pairs) => {
                let mut map = BTreeMap::new();
                for (key, val) in pairs {
                    match key {
                        Sexp::Atom(Atom::Str(s)) => {
                            if map.insert(s, val).is_some() {
                                return Err("duplicate key");
                            }
                        }
                        _ => return Err("key has to be a string"),
                    }
                }
                return Ok(map);
            }
            _ => Err("expr is not a Sexp::Map"),
        }
    }

    pub fn get_uint(&self) -> Option<u64> {
        match self {
            &Sexp::Atom(Atom::UInt(u)) => Some(u),
            _ => None,
        }
    }

    pub fn get_int(&self) -> Option<i64> {
        match self {
            &Sexp::Atom(Atom::SInt(s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_float(&self) -> Option<f64> {
        match self {
            &Sexp::Atom(Atom::Float(f)) => Some(f),
            _ => None,
        }
    }

    pub fn get_str(&self) -> Option<&str> {
        match self {
            &Sexp::Atom(Atom::Str(ref s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_vec<'a, F, R>(&'a self, f: F) -> Option<Vec<R>>
        where F: Fn(&'a Sexp) -> Option<R>
    {
        match self {
            &Sexp::Array(ref ary) => {
                let mut a = Vec::new();
                for elm in ary.iter() {
                    if let Some(u) = f(elm) {
                        a.push(u);
                    } else {
                        return None;
                    }
                }
                Some(a)
            }
            _ => None,
        }
    }

    pub fn get_uint_vec(&self) -> Option<Vec<u64>> {
        self.get_vec(|elm| elm.get_uint())
    }

    pub fn parse_iter<'a, I>(mut iter: I) -> Result<Sexp, ()>
        where I: Iterator<Item = Token<'a>>
    {
        if let Ok(expr) = parser::parse_sexp(&mut iter) {
            if parser::at_end(&mut iter) {
                return Ok(expr);
            }
        }
        Err(())
    }

    pub fn parse(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(Tokenizer::new(s, true))
    }

    pub fn parse_toplevel(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(CurlyAroundTokenizer::new(Tokenizer::new(s, true)))
    }
}

impl<T> From<T> for Sexp where T: Into<Atom>
{
    fn from(t: T) -> Sexp {
        Sexp::Atom(t.into())
    }
}

impl From<()> for Sexp {
    fn from(_e: ()) -> Sexp {
        Sexp::Tuple(vec![])
    }
}

impl<A> From<(A,)> for Sexp where A: Into<Sexp>
{
    fn from(e: (A,)) -> Sexp {
        Sexp::Tuple(vec![e.0.into()])
    }
}

impl<A, B> From<(A, B)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>
{
    fn from(e: (A, B)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into()])
    }
}

impl<A, B, C> From<(A, B, C)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>
{
    fn from(e: (A, B, C)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into()])
    }
}

impl<A, B, C, D> From<(A, B, C, D)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>,
          D: Into<Sexp>
{
    fn from(e: (A, B, C, D)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into(), e.3.into()])
    }
}

impl<A> From<Vec<A>> for Sexp where A: Into<Sexp>
{
    fn from(arr: Vec<A>) -> Sexp {
        Sexp::Array(arr.into_iter().map(|e| e.into()).collect())
    }
}

pub fn prettyprint(sexp: &Sexp,
                   f: &mut fmt::Formatter,
                   indent: usize,
                   newline: bool)
                   -> Result<(), fmt::Error> {
    use std::cmp;

    if newline {
        for _ in 0..cmp::min(4, indent) {
            try!(write!(f, "\n{:>4}", ""));
        }
    }

    match *sexp {
        Sexp::Atom(ref a) => write!(f, "{}", a),
        Sexp::Tuple(ref t) => {
            try!(write!(f, "("));
            for (i, expr) in t.iter().enumerate() {
                if i > 0 {
                    try!(write!(f, " "));
                }
                try!(prettyprint(expr, f, indent, false));
            }
            write!(f, ")")
        }
        Sexp::Array(ref t) => {
            try!(write!(f, "["));
            for (_, expr) in t.iter().enumerate() {
                try!(prettyprint(expr, f, indent + 1, true));
            }
            write!(f, "\n]")
        }
        Sexp::Map(ref t) => {
            try!(write!(f, "{}", "{"));
            for (i, expr) in t.iter().enumerate() {
                if i > 0 {
                    try!(write!(f, " "));
                }
                try!(prettyprint(&expr.0, f, indent, false));
                try!(write!(f, " "));
                try!(prettyprint(&expr.1, f, indent, false));
            }
            write!(f, "{}", "}")
        }
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Sexp::Atom(ref a) => write!(f, "{}", a),
            Sexp::Tuple(ref t) => {
                try!(write!(f, "("));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, ")")
            }
            Sexp::Array(ref t) => {
                try!(write!(f, "["));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, "]")
            }
            Sexp::Map(ref t) => {
                try!(write!(f, "{}", "{"));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{} {}", space, expr.0, expr.1));
                }
                write!(f, "{}", "}")
            }
        }
    }
}

#[test]
fn test_display() {
    assert_eq!("12345", &format!("{}", Sexp::Atom(Atom::UInt(12345))));
    assert_eq!("1.0", &format!("{}", Sexp::Atom(Atom::Float(1.0))));

    assert_eq!("(12345)",
               &format!("{}", Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345))])));
    assert_eq!("(12345 abc)",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Atom(Atom::Str("abc".to_string()))])));
    assert_eq!("(12345 (abc))",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Tuple(vec![
                                         Sexp::Atom(Atom::Str("abc".to_string()))
                                         ])])));

}

#[test]
fn test_from() {
    assert_eq!(Sexp::Atom(Atom::UInt(123)), Sexp::from(123u64));
    assert_eq!(Sexp::Atom(Atom::SInt(123)), Sexp::from(123i64));
    assert_eq!(Sexp::Atom(Atom::Str("test".to_string())),
               Sexp::from("test"));
    assert_eq!(Sexp::Atom(Atom::Float(123.45)), Sexp::from(123.45));
    assert_eq!(Sexp::Tuple(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from((123.45,)));
    assert_eq!(Sexp::Array(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from(vec![123.45]));

}

#[test]
fn test_parse() {
    assert_eq!(Ok(Sexp::from(("abc", 123u64, ("-", 123.43, 11.0)))),
               Sexp::parse("(abc 123 (- 123.43 11.0))"));
}

#[test]
fn test_parse_toplevel() {
    assert_eq!(Sexp::parse("{a 1 b 2}"), Sexp::parse_toplevel("a 1 b 2"));
}

#[test]
fn test_map() {
    let map = Sexp::parse("{a 1 b 2}").unwrap().into_map().unwrap();
    assert_eq!(true, map.contains_key("a"));
    assert_eq!(true, map.contains_key("b"));
    assert_eq!(false, map.contains_key("c"));

    assert_eq!(Err("duplicate key"),
               Sexp::parse("{a 1 b 2 a 1}").unwrap().into_map());
    assert_eq!(Err("key has to be a string"),
               Sexp::parse("{1 1 b 2 a 1}").unwrap().into_map());

}
<|endoftext|>


<commit_before>#[cfg(openexr)]
extern crate openexr;

use std::path::Path;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};

use img;
#[cfg(openexr)]
use openexr::{FrameBufferMut, InputFile};

use Point2i;
use errors::*;
use spectrum::Spectrum;

pub fn read_image<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading image {}", path.as_ref().display());
    let path = path.as_ref();
    let extension = path.extension()
        .ok_or("Texture filename doesn't have an extension")?;
    if extension == "tga" || extension == "TGA" || extension == "png" || extension == "PNG" {
        read_image_tga_png(path)
    } else if extension == "exr" || extension == "EXR" {
        read_image_exr(path)
    } else if extension == "pfm" {
        read_image_pfm(path)
    } else {
        bail!("Unsupported file format");
    }
}

fn read_image_tga_png<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading texture {}", path.as_ref().display());
    let buf = img::open(path)?;

    let rgb = buf.to_rgb();
    let res = Point2i::new(rgb.width() as i32, rgb.height() as i32);
    let pixels: Vec<Spectrum> = rgb.pixels()
        .map(|p| Spectrum::from_srgb(&p.data))
        .collect();

    Ok((pixels, res))
}

#[cfg(not(openexr))]
fn read_image_exr<P: AsRef<Path>>(_path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    panic!("EXR support is not compiled in. Please recompile with the \"openexr\" feature.")
}

#[cfg(openexr)]
fn read_image_exr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading EXR texture {}", path.as_ref().display());
    let mut file = File::open(path.as_ref())?;
    let mut exr_file = InputFile::new(&mut file).unwrap();
    let (width, height) = {
        let window = exr_file.header().data_window();
        let width = window.max.x - window.min.x + 1;
        let height = window.max.y - window.min.y + 1;
        (width, height)
    };

    let mut pixel_data: Vec<(f32, f32, f32)> = vec![(0.0, 0.0, 0.0); (width * height) as usize];

    {
        let mut fb = {
            // Create the frame buffer
            let mut fb = FrameBufferMut::new(width as usize, height as usize);
            fb.insert_channels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
            fb
        };

        exr_file.read_pixels(&mut fb).unwrap();
    }

    let pixels = pixel_data
        .iter()
        .map(|&(r, g, b)| Spectrum::rgb(r, g, b))
        .collect();
    Ok((pixels, Point2i::new(width, height)))
}

fn is_whitespace(c: char) -> bool {
    c == ' ' || c == '\n' || c == '\t'
}

fn read_word<R: BufRead>(f: &mut R) -> String {
    let mut buf = String::new();
    for c in f.bytes() {
        let c = c.unwrap() as char;
        if is_whitespace(c) {
            break;
        }
        buf.push(c);
    }

    buf
}

fn read_image_pfm<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading PFM file {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let mut reader = BufReader::new(file);
    let mut word;

    word = read_word(&mut reader);
    let n_channels = if &word == "Pf" {
        1
    } else if &word == "PF" {
        3
    } else {
        bail!("Error reading PFM file \"{}\"", path.as_ref().display());
    };

    // Read the rest of the header
    // Read width
    word = read_word(&mut reader);
    let width: usize = word.parse().chain_err(|| "Failed to parse width")?;

    // Read height
    word = read_word(&mut reader);
    let height: usize = word.parse().chain_err(|| "Failed to parse height")?;

    // Read scale
    word = read_word(&mut reader);
    let scale: f32 = word.parse().chain_err(|| "Failed to parse scale")?;
    let file_little_endian = scale < 0.0;
    let host_little_endian = true;

    info!("n_channels={}, width={}, height={}, scale={}",
          n_channels,
          width,
          height,
          scale);

    // Read the rest of the data
    let n_floats = n_channels * width * height;
    let mut data = Vec::new();
    data.resize(n_floats, 0.0f32);
    // Flip in Y, as P*M has the origin at the lower left.
    for y in (0..height).rev() {
        for x in 0..width {
            for idx in 0..n_channels {
                let mut buf = [0u8; 4]; // buffer to read a float
                reader.read_exact(&mut buf)?;
                if host_little_endian ^ file_little_endian {
                    buf.as_mut().swap(0, 3);
                    buf.as_mut().swap(1, 2);
                }
                let mut float = unsafe { ::std::mem::transmute::<[u8; 4], f32>(buf) };
                if scale.abs() != 1.0 {
                    float *= scale.abs();
                }
                data[y * n_channels * width + x * n_channels + idx] = float;
            }
        }
    }

    let rgb: Vec<Spectrum> = if n_channels == 1 {
        data.iter().map(|v| Spectrum::from(*v)).collect()
    } else {
        data.chunks(3)
            .map(|rgb| Spectrum::rgb(rgb[0], rgb[1], rgb[2]))
            .collect()
    };

    Ok((rgb, Point2i::new(width as i32, height as i32)))
}
<commit_msg>Seems like TGA files shouldn't be gamma corrected...<commit_after>#[cfg(openexr)]
extern crate openexr;

use std::path::Path;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};

use img;
#[cfg(openexr)]
use openexr::{FrameBufferMut, InputFile};

use Point2i;
use errors::*;
use spectrum::Spectrum;

pub fn read_image<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading image {}", path.as_ref().display());
    let path = path.as_ref();
    let extension = path.extension()
        .ok_or("Texture filename doesn't have an extension")?;
    if extension == "tga" || extension == "TGA" || extension == "png" || extension == "PNG" {
        read_image_tga_png(path)
    } else if extension == "exr" || extension == "EXR" {
        read_image_exr(path)
    } else if extension == "pfm" {
        read_image_pfm(path)
    } else {
        bail!("Unsupported file format");
    }
}

fn read_image_tga_png<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading texture {}", path.as_ref().display());
    let buf = img::open(path)?;

    let rgb = buf.to_rgb();
    let res = Point2i::new(rgb.width() as i32, rgb.height() as i32);
    let pixels: Vec<Spectrum> = rgb.pixels()
        .map(|p| {
            let r = f32::from(p.data[0]) / 255.0;
            let g = f32::from(p.data[1]) / 255.0;
            let b = f32::from(p.data[2]) / 255.0;
            Spectrum::rgb(r, g, b)
        })
        .collect();

    Ok((pixels, res))
}

#[cfg(not(openexr))]
fn read_image_exr<P: AsRef<Path>>(_path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    panic!("EXR support is not compiled in. Please recompile with the \"openexr\" feature.")
}

#[cfg(openexr)]
fn read_image_exr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading EXR texture {}", path.as_ref().display());
    let mut file = File::open(path.as_ref())?;
    let mut exr_file = InputFile::new(&mut file).unwrap();
    let (width, height) = {
        let window = exr_file.header().data_window();
        let width = window.max.x - window.min.x + 1;
        let height = window.max.y - window.min.y + 1;
        (width, height)
    };

    let mut pixel_data: Vec<(f32, f32, f32)> = vec![(0.0, 0.0, 0.0); (width * height) as usize];

    {
        let mut fb = {
            // Create the frame buffer
            let mut fb = FrameBufferMut::new(width as usize, height as usize);
            fb.insert_channels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
            fb
        };

        exr_file.read_pixels(&mut fb).unwrap();
    }

    let pixels = pixel_data
        .iter()
        .map(|&(r, g, b)| Spectrum::rgb(r, g, b))
        .collect();
    Ok((pixels, Point2i::new(width, height)))
}

fn is_whitespace(c: char) -> bool {
    c == ' ' || c == '\n' || c == '\t'
}

fn read_word<R: BufRead>(f: &mut R) -> String {
    let mut buf = String::new();
    for c in f.bytes() {
        let c = c.unwrap() as char;
        if is_whitespace(c) {
            break;
        }
        buf.push(c);
    }

    buf
}

fn read_image_pfm<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading PFM file {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let mut reader = BufReader::new(file);
    let mut word;

    word = read_word(&mut reader);
    let n_channels = if &word == "Pf" {
        1
    } else if &word == "PF" {
        3
    } else {
        bail!("Error reading PFM file \"{}\"", path.as_ref().display());
    };

    // Read the rest of the header
    // Read width
    word = read_word(&mut reader);
    let width: usize = word.parse().chain_err(|| "Failed to parse width")?;

    // Read height
    word = read_word(&mut reader);
    let height: usize = word.parse().chain_err(|| "Failed to parse height")?;

    // Read scale
    word = read_word(&mut reader);
    let scale: f32 = word.parse().chain_err(|| "Failed to parse scale")?;
    let file_little_endian = scale < 0.0;
    let host_little_endian = true;

    info!(
        "n_channels={}, width={}, height={}, scale={}",
        n_channels,
        width,
        height,
        scale
    );

    // Read the rest of the data
    let n_floats = n_channels * width * height;
    let mut data = Vec::new();
    data.resize(n_floats, 0.0f32);
    // Flip in Y, as P*M has the origin at the lower left.
    for y in (0..height).rev() {
        for x in 0..width {
            for idx in 0..n_channels {
                let mut buf = [0u8; 4]; // buffer to read a float
                reader.read_exact(&mut buf)?;
                if host_little_endian ^ file_little_endian {
                    buf.as_mut().swap(0, 3);
                    buf.as_mut().swap(1, 2);
                }
                let mut float = unsafe { ::std::mem::transmute::<[u8; 4], f32>(buf) };
                if scale.abs() != 1.0 {
                    float *= scale.abs();
                }
                data[y * n_channels * width + x * n_channels + idx] = float;
            }
        }
    }

    let rgb: Vec<Spectrum> = if n_channels == 1 {
        data.iter().map(|v| Spectrum::from(*v)).collect()
    } else {
        data.chunks(3)
            .map(|rgb| Spectrum::rgb(rgb[0], rgb[1], rgb[2]))
            .collect()
    };

    Ok((rgb, Point2i::new(width as i32, height as i32)))
}
<|endoftext|>


<commit_before>use super::widgets::{Widget, WidgetStream};
use crate::text::{Attributes, Text};
use alsa::mixer::{SelemChannelId, SelemId};
use alsa::{self, Mixer, PollDescriptors};
use anyhow::Result;
use mio::unix::SourceFd;
use mio::{event, Interest, Registry, Token};
use std::io;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::unix::AsyncFd;
use tokio_stream::{Stream, StreamExt};

/// Shows the current volume of the default ALSA output.
///
/// This widget shows the current volume of the default ALSA output, or '`M`' if
/// the output is muted.
///
/// The widget uses `alsa-lib` to receive events when the volume changes,
/// avoiding expensive polling. If you do not have `alsa-lib` installed, you
/// can disable the `volume-widget` feature on the `cnx` crate to avoid
/// compiling this widget.
pub struct Volume {
    attr: Attributes,
}

impl Volume {
    /// Creates a new Volume widget.
    ///
    /// Creates a new `Volume` widget, whose text will be displayed
    /// with the given [`Attributes`].
    ///
    /// The [`Cnx`] instance is borrowed during construction in order to get
    /// access to handles of its event loop. However, it is not borrowed for the
    /// lifetime of the widget. See the [`cnx_add_widget!()`] for more discussion
    /// about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// #
    /// # fn run() -> ::cnx::Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top)?;
    /// cnx_add_widget!(cnx, Volume::new(&cnx, attr.clone()));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(attr: Attributes) -> Volume {
        Volume { attr }
    }
}

// https://github.com/mjkillough/cnx/blob/92c24238be541c75d88181208862505739be33fd/src/widgets/volume.rs

impl Widget for Volume {
    fn into_stream(self: Box<Self>) -> Result<WidgetStream> {
        let mixer_name = "default";
        // We don't attempt to use the same mixer to listen for events and to
        // recompute the mixer state (in the callback below) as the Mixer seems
        // to cache the state from when it was created. It's relatively cheap
        // create a new mixer each time we get an event though.
        let mixer = Mixer::new(mixer_name, true)?;
        // .with_context(|_| format!("Failed to open ALSA mixer: {}", mixer_name))?;
        let stream = AlsaEventStream::new(mixer).unwrap().map(move |()| {
            // FrontLeft has special meaning in ALSA and is the channel
            // that's used when the mixer is mono.
            let channel = SelemChannelId::FrontLeft;

            let mixer = Mixer::new(mixer_name, true)?;
            let master = mixer.find_selem(&SelemId::new("Master", 0)).unwrap();
            // .ok_or_else(|| format_err!("Couldn't open Master channel"))?;

            let mute = master.get_playback_switch(channel)? == 0;

            let text = if !mute {
                let volume = master.get_playback_volume(channel)?;
                let (min, max) = master.get_playback_volume_range();
                let percentage = (volume as f64 / (max as f64 - min as f64)) * 100.0;
                format!("\\61478 {:.0}%", percentage)
            } else {
                "M".to_owned()
            };

            Ok(vec![Text {
                attr: self.attr.clone(),
                text: text,
                stretch: false,
                markup: false,
            }])
        });

        Ok(Box::pin(stream))
    }
}

struct AlsaEvented(Mixer);

impl AlsaEvented {
    fn mixer(&self) -> &Mixer {
        &self.0
    }

    fn fds(&self) -> Vec<RawFd> {
        self.0
            .get()
            .unwrap()
            .iter()
            .map(|pollfd| pollfd.fd)
            .collect()
    }
}

impl event::Source for AlsaEvented {
    fn register(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        for fd in &self.fds() {
            SourceFd(fd).register(registry, token, interests)?
        }
        Ok(())
    }

    fn reregister(
        &mut self,
        registry: &Registry,
        token: Token,
        interests: Interest,
    ) -> io::Result<()> {
        for fd in &self.fds() {
            SourceFd(fd).reregister(registry, token, interests);
        }
        Ok(())
    }

    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
        // XXX If the set of fds changes (it won't), should we deregister the
        // original set?
        for fd in &self.fds() {
            SourceFd(fd).deregister(registry);
        }
        Ok(())
    }
}

struct AlsaEventStream {
    poll: AsyncFd<AlsaEvented>,
    initial: bool,
}

impl AsRawFd for AlsaEvented {
    fn as_raw_fd(&self) -> RawFd {
        // todo: is this even correce
        self.fds().clone().into_iter().nth(0).unwrap()
    }
}

// I'm porting one of the crates tokio 0.2 series. Since PollEvented is removed, I'm using AsyncFd for most of them and it works well. But in one of the cases - I have to watch a bucn

impl AlsaEventStream {
    fn new(mixer: Mixer) -> Result<AlsaEventStream> {
        Ok(AlsaEventStream {
            poll: AsyncFd::new(AlsaEvented(mixer))?,
            // The first few calls to poll() need to process any existing events.
            // We don't know what state the fds are in when we give them to tokio
            // and it's edge-triggered.
            initial: true,
        })
    }
}

impl Stream for AlsaEventStream {
    // We don't bother yielding the events and just yield unit each time we get
    // an event. This stream is used only to get woken up when the ALSA state
    // changes - the caller is expected to requery all necessary state when
    // it receives a new item from the stream.
    type Item = ();

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        // Always assume we're ready initially, so that we can clear the
        // state of the fds.
        if !self.initial {
            if let Poll::Pending = self.poll.poll_read_ready(cx) {
                return Poll::Pending;
            }
        }
        self.initial = false;

        // Do a poll with a timeout of 0 to figure out exactly which fds were
        // woken up, followed by a call to revents() which clears the pending
        // events. We don't actually care what the events are - we're just
        // using it as a wake-up so we can check the volume again.
        let mixer = self.poll.get_ref().mixer();
        let ready = alsa::poll::poll_all(&[mixer], 0).unwrap();
        let poll_descriptors = ready.into_iter().map(|(p, _)| p);
        for poll_descriptor in poll_descriptors {
            mixer
                .revents(poll_descriptor.get().unwrap().as_slice())
                .unwrap();
        }
        // All events have been consumed - tell Tokio we're interested in waiting
        // for more again.
        // todo
        // self.poll.need_read();

        Poll::Ready(Some(()))
    }
}
<commit_msg>Remove volume_linux.rs<commit_after><|endoftext|>


<commit_before>#![feature(io)]
#![allow(dead_code)]

use std::io::{Read, Write};
use std::thread;

struct Client<R, W> where R: Read, W: Write {
    r: R,
    w: W,
}

impl<R, W> Client<R, W> where R: Read + Send, W: Write + Send {
    pub fn new(r: R, w: W) -> Client<R, W> {
        let mut client = Client{ r: r, w: w };
        client.listen();
        client
    }

    fn listen(&mut self) {
        thread::scoped(|| {
            let mut buf = [0 as u8; 1024];
            loop {
                match self.r.read(&mut buf) {
                    Ok(read) => println!("read {} bytes", read),
                    Err(..) => println!("fuck"),
                }
            }
        });
    }
}

fn main() {}
<commit_msg>Remove test file.<commit_after><|endoftext|>