<commit_before>use ansi_term::{ANSIString, Style};

use fs::{File, FileTarget};
use output::Colours;
use output::cell::TextCellContents;

pub struct FileName<'a, 'dir: 'a> {
    file:    &'a File<'dir>,
    colours: &'a Colours,
}

impl<'a, 'dir> FileName<'a, 'dir> {
    pub fn new(file: &'a File<'dir>, colours: &'a Colours) -> FileName<'a, 'dir> {
        FileName {
            file: file,
            colours: colours,
        }
    }

    pub fn file_name(&self, links: bool, classify: bool) -> TextCellContents {
        let mut bits = Vec::new();

        if self.file.dir.is_none() {
            if let Some(parent) = self.file.path.parent() {
                let coconut = parent.components().count();

                if coconut == 1 && parent.has_root() {
                    bits.push(self.colours.symlink_path.paint("/"));
                }
                else if coconut >= 1 {
                    bits.push(self.colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                    bits.push(self.colours.symlink_path.paint("/"));
                }
            }
        }

        if !self.file.name.is_empty() {
            for bit in self.coloured_file_name() {
                bits.push(bit);
            }
        }

        if links && self.file.is_link() {
            match self.file.link_target() {
                FileTarget::Ok(target) => {
                    bits.push(Style::default().paint(" "));
                    bits.push(self.colours.punctuation.paint("->"));
                    bits.push(Style::default().paint(" "));

                    if let Some(parent) = target.path.parent() {
                        let coconut = parent.components().count();

                        if coconut == 1 && parent.has_root() {
                            bits.push(self.colours.symlink_path.paint("/"));
                        }
                        else if coconut >= 1 {
                            bits.push(self.colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                            bits.push(self.colours.symlink_path.paint("/"));
                        }
                    }

                    if !target.name.is_empty() {
                        bits.push(FileName::new(&target, self.colours).file_colour().paint(target.name));
                    }
                },

                FileTarget::Broken(broken_path) => {
                    bits.push(Style::default().paint(" "));
                    bits.push(self.colours.broken_arrow.paint("->"));
                    bits.push(Style::default().paint(" "));
                    bits.push(self.colours.broken_filename.paint(broken_path.display().to_string()));
                },

                FileTarget::Err(_) => {
                    // Do nothing -- the error gets displayed on the next line
                }
            }
        }
        else if classify {
            if let Some(class) = self.classify_char() {
                bits.push(Style::default().paint(class));
            }
        }

        bits.into()
    }

    fn classify_char(&self) -> Option<&'static str> {
        if self.file.is_executable_file() {
            Some("*")
        } else if self.file.is_directory() {
            Some("/")
        } else if self.file.is_pipe() {
            Some("|")
        } else if self.file.is_link() {
            Some("@")
        } else if self.file.is_socket() {
            Some("=")
        } else {
            None
        }
    }

    /// Returns at least one ANSI-highlighted string representing this file’s
    /// name using the given set of colours.
    ///
    /// Ordinarily, this will be just one string: the file’s complete name,
    /// coloured according to its file type. If the name contains control
    /// characters such as newlines or escapes, though, we can’t just print them
    /// to the screen directly, because then there’ll be newlines in weird places.
    ///
    /// So in that situation, those characters will be escaped and highlighted in
    /// a different colour.
    fn coloured_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
        let colour = self.file_colour();
        let mut bits = Vec::new();

        if self.file.name.chars().all(|c| c >= 0x20 as char) {
            bits.push(colour.paint(self.file.name.clone()));
        }
        else {
            for c in self.file.name.chars() {
                // The `escape_default` method on `char` is *almost* what we want here, but
                // it still escapes non-ASCII UTF-8 characters, which are still printable.

                if c >= 0x20 as char {
                    // TODO: This allocates way too much,
                    // hence the `all` check above.
                    let mut s = String::new();
                    s.push(c);
                    bits.push(colour.paint(s));
                } else {
                    let s = c.escape_default().collect::<String>();
                    bits.push(self.colours.control_char.paint(s));
                }
            }
        }

        bits
    }

    pub fn file_colour(&self) -> Style {
        match self.file {
            f if f.is_directory()        => self.colours.filetypes.directory,
            f if f.is_executable_file()  => self.colours.filetypes.executable,
            f if f.is_link()             => self.colours.filetypes.symlink,
            f if f.is_pipe()             => self.colours.filetypes.pipe,
            f if f.is_char_device()
               | f.is_block_device()     => self.colours.filetypes.device,
            f if f.is_socket()           => self.colours.filetypes.socket,
            f if !f.is_file()            => self.colours.filetypes.special,
            f if f.is_immediate()        => self.colours.filetypes.immediate,
            f if f.is_image()            => self.colours.filetypes.image,
            f if f.is_video()            => self.colours.filetypes.video,
            f if f.is_music()            => self.colours.filetypes.music,
            f if f.is_lossless()         => self.colours.filetypes.lossless,
            f if f.is_crypto()           => self.colours.filetypes.crypto,
            f if f.is_document()         => self.colours.filetypes.document,
            f if f.is_compressed()       => self.colours.filetypes.compressed,
            f if f.is_temp()             => self.colours.filetypes.temp,
            f if f.is_compiled()         => self.colours.filetypes.compiled,
            _                            => self.colours.filetypes.normal,
        }
    }
}
<commit_msg>A file’s colour is actually a style<commit_after>use ansi_term::{ANSIString, Style};

use fs::{File, FileTarget};
use output::Colours;
use output::cell::TextCellContents;

pub struct FileName<'a, 'dir: 'a> {
    file:    &'a File<'dir>,
    colours: &'a Colours,
}

impl<'a, 'dir> FileName<'a, 'dir> {
    pub fn new(file: &'a File<'dir>, colours: &'a Colours) -> FileName<'a, 'dir> {
        FileName {
            file: file,
            colours: colours,
        }
    }

    pub fn file_name(&self, links: bool, classify: bool) -> TextCellContents {
        let mut bits = Vec::new();

        if self.file.dir.is_none() {
            if let Some(parent) = self.file.path.parent() {
                let coconut = parent.components().count();

                if coconut == 1 && parent.has_root() {
                    bits.push(self.colours.symlink_path.paint("/"));
                }
                else if coconut >= 1 {
                    bits.push(self.colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                    bits.push(self.colours.symlink_path.paint("/"));
                }
            }
        }

        if !self.file.name.is_empty() {
            for bit in self.coloured_file_name() {
                bits.push(bit);
            }
        }

        if links && self.file.is_link() {
            match self.file.link_target() {
                FileTarget::Ok(target) => {
                    bits.push(Style::default().paint(" "));
                    bits.push(self.colours.punctuation.paint("->"));
                    bits.push(Style::default().paint(" "));

                    if let Some(parent) = target.path.parent() {
                        let coconut = parent.components().count();

                        if coconut == 1 && parent.has_root() {
                            bits.push(self.colours.symlink_path.paint("/"));
                        }
                        else if coconut >= 1 {
                            bits.push(self.colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                            bits.push(self.colours.symlink_path.paint("/"));
                        }
                    }

                    if !target.name.is_empty() {
                        bits.push(FileName::new(&target, self.colours).style().paint(target.name));
                    }
                },

                FileTarget::Broken(broken_path) => {
                    bits.push(Style::default().paint(" "));
                    bits.push(self.colours.broken_arrow.paint("->"));
                    bits.push(Style::default().paint(" "));
                    bits.push(self.colours.broken_filename.paint(broken_path.display().to_string()));
                },

                FileTarget::Err(_) => {
                    // Do nothing -- the error gets displayed on the next line
                }
            }
        }
        else if classify {
            if let Some(class) = self.classify_char() {
                bits.push(Style::default().paint(class));
            }
        }

        bits.into()
    }

    fn classify_char(&self) -> Option<&'static str> {
        if self.file.is_executable_file() {
            Some("*")
        } else if self.file.is_directory() {
            Some("/")
        } else if self.file.is_pipe() {
            Some("|")
        } else if self.file.is_link() {
            Some("@")
        } else if self.file.is_socket() {
            Some("=")
        } else {
            None
        }
    }

    /// Returns at least one ANSI-highlighted string representing this file’s
    /// name using the given set of colours.
    ///
    /// Ordinarily, this will be just one string: the file’s complete name,
    /// coloured according to its file type. If the name contains control
    /// characters such as newlines or escapes, though, we can’t just print them
    /// to the screen directly, because then there’ll be newlines in weird places.
    ///
    /// So in that situation, those characters will be escaped and highlighted in
    /// a different colour.
    fn coloured_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
        let file_style = self.style();
        let mut bits = Vec::new();

        if self.file.name.chars().all(|c| c >= 0x20 as char) {
            bits.push(file_style.paint(self.file.name.clone()));
        }
        else {
            for c in self.file.name.chars() {
                // The `escape_default` method on `char` is *almost* what we want here, but
                // it still escapes non-ASCII UTF-8 characters, which are still printable.

                if c >= 0x20 as char {
                    // TODO: This allocates way too much,
                    // hence the `all` check above.
                    let mut s = String::new();
                    s.push(c);
                    bits.push(file_style.paint(s));
                } else {
                    let s = c.escape_default().collect::<String>();
                    bits.push(self.colours.control_char.paint(s));
                }
            }
        }

        bits
    }

    pub fn style(&self) -> Style {
        match self.file {
            f if f.is_directory()        => self.colours.filetypes.directory,
            f if f.is_executable_file()  => self.colours.filetypes.executable,
            f if f.is_link()             => self.colours.filetypes.symlink,
            f if f.is_pipe()             => self.colours.filetypes.pipe,
            f if f.is_char_device()
               | f.is_block_device()     => self.colours.filetypes.device,
            f if f.is_socket()           => self.colours.filetypes.socket,
            f if !f.is_file()            => self.colours.filetypes.special,
            f if f.is_immediate()        => self.colours.filetypes.immediate,
            f if f.is_image()            => self.colours.filetypes.image,
            f if f.is_video()            => self.colours.filetypes.video,
            f if f.is_music()            => self.colours.filetypes.music,
            f if f.is_lossless()         => self.colours.filetypes.lossless,
            f if f.is_crypto()           => self.colours.filetypes.crypto,
            f if f.is_document()         => self.colours.filetypes.document,
            f if f.is_compressed()       => self.colours.filetypes.compressed,
            f if f.is_temp()             => self.colours.filetypes.temp,
            f if f.is_compiled()         => self.colours.filetypes.compiled,
            _                            => self.colours.filetypes.normal,
        }
    }
}
<|endoftext|>


<commit_before>use evaluation::Level;
use names;
use types::PokeType;

mod generated_species;
use self::generated_species::SPECIES;

#[derive(Debug, Eq, PartialEq, Hash)]
/// Information about a specific Pokemon species.
pub struct Species {
    id: u16,
    attack: u16,
    defense: u16,
    stamina: u16,
    primary_type: PokeType,
    secondary_type: Option<PokeType>,
}

impl Species {
    /// Fetch a `Species` using a `PokeName` constant.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::Species;
    /// use pokemon_go_data::names;
    ///
    /// let vulpix = Species::named(names::Vulpix);
    /// assert_eq!(37, vulpix.id());
    /// ```
    pub fn named(name: names::PokeName) -> &'static Species {
        &SPECIES[(name.id() - 1) as usize]
    }

    /// Given the id of a species, return its corresponding data. Return `None` if no data is found
    /// for the given id.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::Species;
    ///
    /// let dragonite = Species::from_id(149).unwrap();
    /// assert_eq!((263, 201, 182), dragonite.base_stats());
    ///
    /// let no_such_pokemon = Species::from_id(500);
    /// assert!(no_such_pokemon.is_none());
    /// ```
    pub fn from_id(id: u16) -> Option<&'static Species> {
        SPECIES.iter().find(|p| p.id() == id)
    }

    /// Return a list of all `Species`, sorted by id.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::Species;
    ///
    /// let all_species = Species::all_species();
    ///
    /// assert_eq!(251, all_species.len());
    /// assert_eq!(1, all_species[0].id());
    /// ```
    pub fn all_species() -> &'static [Species] {
        SPECIES
    }

    /// This species' id.
    pub fn id(&self) -> u16 {
        self.id
    }

    /// This species' base attack value.
    pub fn attack(&self) -> u16 {
        self.attack
    }

    /// This species's base defense value.
    pub fn defense(&self) -> u16 {
        self.defense
    }

    /// This species' base stamina value.
    pub fn stamina(&self) -> u16 {
        self.stamina
    }

    /// This species' base stats, as an `(attack, defense, stamina)` triple.
    pub fn base_stats(&self) -> (u16, u16, u16) {
        (self.attack, self.defense, self.stamina)
    }

    /// This species' primary `PokeType`.
    pub fn primary_type(&self) -> PokeType {
        self.primary_type
    }

    /// If this species is dual-typed, returns the secondary `PokeType`.
    pub fn secondary_type(&self) -> Option<PokeType> {
        self.secondary_type
    }

    /// Returns `true` if this species has two `PokeType`s.
    pub fn is_dual_type(&self) -> bool {
        self.secondary_type.is_some()
    }

    /// Returns the highest possible stats for this pokemon (e.g., perfect IVs).
    pub fn perfect_stats(&self) -> (u16, u16, u16) {
        (self.attack() + 15, self.defense() + 15, self.stamina() + 15)
    }

    /// Returns the species' max Combat Power at the given `Level`, assuming perfect IVs.
    pub fn max_cp_at_level(&self, level: Level) -> u16 {
        let (attack, defense, stamina) = self.perfect_stats();

        Species::calculate_cp(attack, defense, stamina, level)
    }

    /// Returns this species' max Combat Power at level 39, assuming perfect IVs.
    pub fn max_cp(&self) -> u16 {
        let (attack, defense, stamina) = self.perfect_stats();

        Species::calculate_cp(attack, defense, stamina, Level::max())
    }

    fn calculate_cp(attack: u16, defense: u16, stamina: u16, level: Level) -> u16 {
        let attack_calc = attack as f64;
        let defense_calc = (defense as f64).sqrt();
        let stamina_calc = (stamina as f64).sqrt();

        let cp_multiplier = level.cp_multiplier().powi(2);

        let inner = attack_calc * defense_calc * stamina_calc * cp_multiplier / 10.;

        ::std::cmp::max(10, inner.floor() as u16)
    }
}

#[cfg(test)]
mod tests {
    use evaluation::Level;
    use names;
    use types::PokeType;
    use Species;

    #[test]
    fn named() {
        let clefable = Species::named(names::Clefable);
        assert_eq!(36, clefable.id());

        let nidoran_male = Species::named(names::NidoranMale);
        assert_eq!(32, nidoran_male.id());
    }

    #[test]
    fn species_by_id() {
        let bulbasaur = Species::from_id(1).unwrap();
        assert_eq!((118, 118, 90), bulbasaur.base_stats());

        let sentret = Species::from_id(161).unwrap();
        assert_eq!((79, 77, 70), sentret.base_stats());

        let lugia = Species::from_id(249).unwrap();
        assert_eq!((193, 323, 212), lugia.base_stats());

        assert!(Species::from_id(252).is_none());
    }

    #[test]
    fn poketype() {
        let charizard = Species::from_id(6).unwrap();
        assert_eq!(PokeType::Fire, charizard.primary_type());
        assert_eq!(Some(PokeType::Flying), charizard.secondary_type());

        let squirtle = Species::from_id(7).unwrap();
        assert_eq!(PokeType::Water, squirtle.primary_type());
        assert!(squirtle.secondary_type().is_none());
    }

    #[test]
    fn all_species() {
        let all_pokemon = Species::all_species();
        let num_pokemon = 251;

        assert_eq!(num_pokemon, all_pokemon.len());

        for i in 0..num_pokemon {
            assert!(
                all_pokemon[i].id() == (i + 1) as u16,
                format!("Couldn't find pokemon #{}", i)
            );
        }
    }

    #[test]
    fn max_cp_at_level() {
        let level = Level::new(20).unwrap();
        let kakuna = Species::from_id(14).unwrap();

        assert_eq!(224, kakuna.max_cp_at_level(level));
    }

    #[test]
    fn max_cp() {
        let eevee = Species::from_id(133).unwrap();
        assert_eq!(955, eevee.max_cp());

        let dragonite = Species::from_id(149).unwrap();
        assert_eq!(3_530, dragonite.max_cp());
    }
}
<commit_msg>Add documentation for max_cp<commit_after>use evaluation::Level;
use names;
use types::PokeType;

mod generated_species;
use self::generated_species::SPECIES;

#[derive(Debug, Eq, PartialEq, Hash)]
/// Information about a specific Pokemon species.
pub struct Species {
    id: u16,
    attack: u16,
    defense: u16,
    stamina: u16,
    primary_type: PokeType,
    secondary_type: Option<PokeType>,
}

impl Species {
    /// Fetch a `Species` using a `PokeName` constant.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::{names, Species};
    ///
    /// let vulpix = Species::named(names::Vulpix);
    /// assert_eq!(37, vulpix.id());
    /// ```
    pub fn named(name: names::PokeName) -> &'static Species {
        &SPECIES[(name.id() - 1) as usize]
    }

    /// Given the id of a species, return its corresponding data. Return `None` if no data is found
    /// for the given id.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::Species;
    ///
    /// let dragonite = Species::from_id(149).unwrap();
    /// assert_eq!((263, 201, 182), dragonite.base_stats());
    ///
    /// let no_such_pokemon = Species::from_id(500);
    /// assert!(no_such_pokemon.is_none());
    /// ```
    pub fn from_id(id: u16) -> Option<&'static Species> {
        SPECIES.iter().find(|p| p.id() == id)
    }

    /// Return a list of all `Species`, sorted by id.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::Species;
    ///
    /// let all_species = Species::all_species();
    ///
    /// assert_eq!(251, all_species.len());
    /// assert_eq!(1, all_species[0].id());
    /// ```
    pub fn all_species() -> &'static [Species] {
        SPECIES
    }

    /// This species' id.
    pub fn id(&self) -> u16 {
        self.id
    }

    /// This species' base attack value.
    pub fn attack(&self) -> u16 {
        self.attack
    }

    /// This species's base defense value.
    pub fn defense(&self) -> u16 {
        self.defense
    }

    /// This species' base stamina value.
    pub fn stamina(&self) -> u16 {
        self.stamina
    }

    /// This species' base stats, as an `(attack, defense, stamina)` triple.
    pub fn base_stats(&self) -> (u16, u16, u16) {
        (self.attack, self.defense, self.stamina)
    }

    /// This species' primary `PokeType`.
    pub fn primary_type(&self) -> PokeType {
        self.primary_type
    }

    /// If this species is dual-typed, returns the secondary `PokeType`.
    pub fn secondary_type(&self) -> Option<PokeType> {
        self.secondary_type
    }

    /// Returns `true` if this species has two `PokeType`s.
    pub fn is_dual_type(&self) -> bool {
        self.secondary_type.is_some()
    }

    /// Returns the highest possible stats for this pokemon (e.g., perfect IVs).
    pub fn perfect_stats(&self) -> (u16, u16, u16) {
        (self.attack() + 15, self.defense() + 15, self.stamina() + 15)
    }

    /// Returns the species' max combat power at the given `Level`, assuming perfect IVs.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::{Level, names, Species};
    ///
    /// let level_30 = Level::new(30).unwrap();
    /// let magikarp = Species::named(names::Magikarp);
    ///
    /// assert_eq!(188, magikarp.max_cp_at_level(level_30));
    /// ```
   pub fn max_cp_at_level(&self, level: Level) -> u16 {
        let (attack, defense, stamina) = self.perfect_stats();

        Species::calculate_cp(attack, defense, stamina, level)
    }

    /// Returns this species' max Combat Power at level 39, assuming perfect IVs.
    ///
    /// ## Example:
    ///
    /// ```
    /// use pokemon_go_data::{names, Species};
    ///
    /// let tyranitar = Species::named(names::Tyranitar);
    /// assert_eq!(3_617, tyranitar.max_cp());
    /// ```
    pub fn max_cp(&self) -> u16 {
        let (attack, defense, stamina) = self.perfect_stats();

        Species::calculate_cp(attack, defense, stamina, Level::max())
    }

    fn calculate_cp(attack: u16, defense: u16, stamina: u16, level: Level) -> u16 {
        let attack_calc = attack as f64;
        let defense_calc = (defense as f64).sqrt();
        let stamina_calc = (stamina as f64).sqrt();

        let cp_multiplier = level.cp_multiplier().powi(2);

        let inner = attack_calc * defense_calc * stamina_calc * cp_multiplier / 10.;

        ::std::cmp::max(10, inner.floor() as u16)
    }
}

#[cfg(test)]
mod tests {
    use evaluation::Level;
    use names;
    use types::PokeType;
    use Species;

    #[test]
    fn named() {
        let clefable = Species::named(names::Clefable);
        assert_eq!(36, clefable.id());

        let nidoran_male = Species::named(names::NidoranMale);
        assert_eq!(32, nidoran_male.id());
    }

    #[test]
    fn species_by_id() {
        let bulbasaur = Species::from_id(1).unwrap();
        assert_eq!((118, 118, 90), bulbasaur.base_stats());

        let sentret = Species::from_id(161).unwrap();
        assert_eq!((79, 77, 70), sentret.base_stats());

        let lugia = Species::from_id(249).unwrap();
        assert_eq!((193, 323, 212), lugia.base_stats());

        assert!(Species::from_id(252).is_none());
    }

    #[test]
    fn poketype() {
        let charizard = Species::from_id(6).unwrap();
        assert_eq!(PokeType::Fire, charizard.primary_type());
        assert_eq!(Some(PokeType::Flying), charizard.secondary_type());

        let squirtle = Species::from_id(7).unwrap();
        assert_eq!(PokeType::Water, squirtle.primary_type());
        assert!(squirtle.secondary_type().is_none());
    }

    #[test]
    fn all_species() {
        let all_pokemon = Species::all_species();
        let num_pokemon = 251;

        assert_eq!(num_pokemon, all_pokemon.len());

        for i in 0..num_pokemon {
            assert!(
                all_pokemon[i].id() == (i + 1) as u16,
                format!("Couldn't find pokemon #{}", i)
            );
        }
    }

    #[test]
    fn max_cp_at_level() {
        let level = Level::new(20).unwrap();
        let kakuna = Species::from_id(14).unwrap();

        assert_eq!(224, kakuna.max_cp_at_level(level));
    }

    #[test]
    fn max_cp() {
        let eevee = Species::from_id(133).unwrap();
        assert_eq!(955, eevee.max_cp());

        let dragonite = Species::from_id(149).unwrap();
        assert_eq!(3_530, dragonite.max_cp());
    }
}
<|endoftext|>


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

use std::sync::{Arc, RwLock, Mutex};
use std::sync::mpsc::Sender;
use std::net::SocketAddr;
use kvproto::raft_serverpb::RaftMessage;
use kvproto::raft_cmdpb::RaftCmdRequest;

use util::transport::SendCh;
use util::HandyRwLock;
use util::worker::{Stopped, Scheduler};
use util::collections::HashSet;
use raft::SnapshotStatus;
use raftstore::store::{Msg as StoreMsg, SnapshotStatusMsg, Transport, Callback};
use raftstore::Result as RaftStoreResult;
use server::raft_client::RaftClient;
use server::Result;
use super::snap::Task as SnapTask;
use super::resolve::StoreAddrResolver;
use super::metrics::*;

pub trait RaftStoreRouter: Send + Clone {
    /// Send StoreMsg, retry if failed. Try times may vary from implementation.
    fn send(&self, msg: StoreMsg) -> RaftStoreResult<()>;

    /// Send StoreMsg.
    fn try_send(&self, msg: StoreMsg) -> RaftStoreResult<()>;

    // Send RaftMessage to local store.
    fn send_raft_msg(&self, msg: RaftMessage) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::RaftMessage(msg))
    }

    // Send RaftCmdRequest to local store.
    fn send_command(&self, req: RaftCmdRequest, cb: Callback) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::new_raft_cmd(req, cb))
    }

    fn report_unreachable(&self, region_id: u64, to_peer_id: u64, _: u64) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::ReportUnreachable {
            region_id: region_id,
            to_peer_id: to_peer_id,
        })
    }
}

#[derive(Clone)]
pub struct ServerRaftStoreRouter {
    pub ch: SendCh<StoreMsg>,
}

impl ServerRaftStoreRouter {
    pub fn new(ch: SendCh<StoreMsg>) -> ServerRaftStoreRouter {
        ServerRaftStoreRouter { ch: ch }
    }
}

impl RaftStoreRouter for ServerRaftStoreRouter {
    fn try_send(&self, msg: StoreMsg) -> RaftStoreResult<()> {
        try!(self.ch.try_send(msg));
        Ok(())
    }

    fn send(&self, msg: StoreMsg) -> RaftStoreResult<()> {
        try!(self.ch.send(msg));
        Ok(())
    }

    fn send_raft_msg(&self, msg: RaftMessage) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::RaftMessage(msg))
    }

    fn send_command(&self, req: RaftCmdRequest, cb: Callback) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::new_raft_cmd(req, cb))
    }

    fn report_unreachable(&self,
                          region_id: u64,
                          to_peer_id: u64,
                          to_store_id: u64)
                          -> RaftStoreResult<()> {
        let store = to_store_id.to_string();
        REPORT_FAILURE_MSG_COUNTER.with_label_values(&["unreachable", &*store]).inc();
        self.try_send(StoreMsg::ReportUnreachable {
            region_id: region_id,
            to_peer_id: to_peer_id,
        })
    }
}

pub struct ServerTransport<T, S>
    where T: RaftStoreRouter + 'static,
          S: StoreAddrResolver + Send + 'static
{
    raft_client: Arc<RwLock<RaftClient>>,
    snap_scheduler: Scheduler<SnapTask>,
    raft_router: T,
    snapshot_status_sender: Sender<SnapshotStatusMsg>,
    resolving: Arc<RwLock<HashSet<u64>>>,
    resolver: Arc<Mutex<S>>,
}

impl<T, S> Clone for ServerTransport<T, S>
    where T: RaftStoreRouter + 'static,
          S: StoreAddrResolver + Send + 'static
{
    fn clone(&self) -> Self {
        ServerTransport {
            raft_client: self.raft_client.clone(),
            snap_scheduler: self.snap_scheduler.clone(),
            raft_router: self.raft_router.clone(),
            snapshot_status_sender: self.snapshot_status_sender.clone(),
            resolving: self.resolving.clone(),
            resolver: self.resolver.clone(),
        }
    }
}

impl<T: RaftStoreRouter + 'static, S: StoreAddrResolver + Send + 'static> ServerTransport<T, S> {
    pub fn new(raft_client: Arc<RwLock<RaftClient>>,
               snap_scheduler: Scheduler<SnapTask>,
               raft_router: T,
               snapshot_status_sender: Sender<SnapshotStatusMsg>,
               resolver: S)
               -> ServerTransport<T, S> {
        ServerTransport {
            raft_client: raft_client,
            snap_scheduler: snap_scheduler,
            raft_router: raft_router,
            snapshot_status_sender: snapshot_status_sender,
            resolving: Arc::new(RwLock::new(Default::default())),
            resolver: Arc::new(Mutex::new(resolver)),
        }
    }

    fn send_store(&self, store_id: u64, msg: RaftMessage) {
        // check the corresponding token for store.
        let addr = self.raft_client.rl().addrs.get(&store_id).cloned();
        if let Some(addr) = addr {
            self.write_data(store_id, addr, msg);
            return;
        }

        // No connection, try to resolve it.
        if self.resolving.rl().contains(&store_id) {
            RESOLVE_STORE_COUNTER.with_label_values(&["resolving"]).inc();
            // If we are resolving the address, drop the message here.
            debug!("store {} address is being resolved, drop msg {:?}",
                   store_id,
                   msg);
            self.report_unreachable(msg);
            return;
        }

        debug!("begin to resolve store {} address", store_id);
        RESOLVE_STORE_COUNTER.with_label_values(&["resolve"]).inc();

        self.resolving.wl().insert(store_id);
        self.resolve(store_id, msg);
    }

    fn resolve(&self, store_id: u64, msg: RaftMessage) {
        let trans = self.clone();
        let cb = box move |addr| {
            // clear resolving.
            trans.resolving.wl().remove(&store_id);

            if let Err(e) = addr {
                RESOLVE_STORE_COUNTER.with_label_values(&["failed"]).inc();
                debug!("resolve store {} address failed {:?}", store_id, e);
                trans.report_unreachable(msg);
                return;
            }

            RESOLVE_STORE_COUNTER.with_label_values(&["success"]).inc();
            let addr = addr.unwrap();
            info!("resolve store {} address ok, addr {}", store_id, addr);
            trans.raft_client.wl().addrs.insert(store_id, addr);
            trans.write_data(store_id, addr, msg);
        };
        if let Err(e) = self.resolver.lock().unwrap().resolve(store_id, cb) {
            error!("try to resolve err {:?}", e);
        }
    }

    fn write_data(&self, store_id: u64, addr: SocketAddr, msg: RaftMessage) {
        if msg.get_message().has_snapshot() {
            return self.send_snapshot_sock(addr, msg);
        }
        if let Err(e) = self.raft_client.wl().send(store_id, addr, msg) {
            error!("send raft msg err {:?}", e);
        }
    }

    fn send_snapshot_sock(&self, sock_addr: SocketAddr, msg: RaftMessage) {
        let rep = self.new_snapshot_reporter(&msg);
        let cb = box move |res: Result<()>| {
            if res.is_err() {
                rep.report(SnapshotStatus::Failure);
            } else {
                rep.report(SnapshotStatus::Finish);
            }
        };
        if let Err(Stopped(SnapTask::SendTo { cb, .. })) = self.snap_scheduler
            .schedule(SnapTask::SendTo {
                addr: sock_addr,
                msg: msg,
                cb: cb,
            }) {
            error!("channel is closed, failed to schedule snapshot to {}",
                   sock_addr);
            cb(Err(box_err!("failed to schedule snapshot")));
        }
    }

    fn new_snapshot_reporter(&self, msg: &RaftMessage) -> SnapshotReporter {
        let region_id = msg.get_region_id();
        let to_peer_id = msg.get_to_peer().get_id();
        let to_store_id = msg.get_to_peer().get_store_id();

        SnapshotReporter {
            snapshot_status_sender: self.snapshot_status_sender.clone(),
            region_id: region_id,
            to_peer_id: to_peer_id,
            to_store_id: to_store_id,
        }
    }

    pub fn report_unreachable(&self, msg: RaftMessage) {
        let region_id = msg.get_region_id();
        let to_peer_id = msg.get_to_peer().get_id();
        let to_store_id = msg.get_to_peer().get_store_id();

        if let Err(e) = self.raft_router.report_unreachable(region_id, to_peer_id, to_store_id) {
            error!("report peer {} unreachable for region {} failed {:?}",
                   to_peer_id,
                   region_id,
                   e);
        }
    }

    pub fn flush_raft_client(&mut self) {
        self.raft_client.wl().flush();
    }
}

impl<T, S> Transport for ServerTransport<T, S>
    where T: RaftStoreRouter + 'static,
          S: StoreAddrResolver + Send + 'static
{
    fn send(&self, msg: RaftMessage) -> RaftStoreResult<()> {
        let to_store_id = msg.get_to_peer().get_store_id();
        self.send_store(to_store_id, msg);
        Ok(())
    }

    fn flush(&mut self) {
        self.flush_raft_client();
    }
}

struct SnapshotReporter {
    snapshot_status_sender: Sender<SnapshotStatusMsg>,
    region_id: u64,
    to_peer_id: u64,
    to_store_id: u64,
}

impl SnapshotReporter {
    pub fn report(&self, status: SnapshotStatus) {
        debug!("send snapshot to {} for {} {:?}",
               self.to_peer_id,
               self.region_id,
               status);

        if status == SnapshotStatus::Failure {
            let store = self.to_store_id.to_string();
            REPORT_FAILURE_MSG_COUNTER.with_label_values(&["snapshot", &*store]).inc();
        };

        if let Err(e) = self.snapshot_status_sender.send(SnapshotStatusMsg {
            region_id: self.region_id,
            to_peer_id: self.to_peer_id,
            status: status,
        }) {
            error!("report snapshot to peer {} in store {} with region {} err {:?}",
                   self.to_peer_id,
                   self.to_store_id,
                   self.region_id,
                   e);
        }
    }
}
<commit_msg>transport: fix possible message delay (#2093)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::{Arc, RwLock, Mutex};
use std::sync::mpsc::Sender;
use std::net::SocketAddr;
use kvproto::raft_serverpb::RaftMessage;
use kvproto::raft_cmdpb::RaftCmdRequest;

use util::transport::SendCh;
use util::HandyRwLock;
use util::worker::{Stopped, Scheduler};
use util::collections::HashSet;
use raft::SnapshotStatus;
use raftstore::store::{Msg as StoreMsg, SnapshotStatusMsg, Transport, Callback};
use raftstore::Result as RaftStoreResult;
use server::raft_client::RaftClient;
use server::Result;
use super::snap::Task as SnapTask;
use super::resolve::StoreAddrResolver;
use super::metrics::*;

pub trait RaftStoreRouter: Send + Clone {
    /// Send StoreMsg, retry if failed. Try times may vary from implementation.
    fn send(&self, msg: StoreMsg) -> RaftStoreResult<()>;

    /// Send StoreMsg.
    fn try_send(&self, msg: StoreMsg) -> RaftStoreResult<()>;

    // Send RaftMessage to local store.
    fn send_raft_msg(&self, msg: RaftMessage) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::RaftMessage(msg))
    }

    // Send RaftCmdRequest to local store.
    fn send_command(&self, req: RaftCmdRequest, cb: Callback) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::new_raft_cmd(req, cb))
    }

    fn report_unreachable(&self, region_id: u64, to_peer_id: u64, _: u64) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::ReportUnreachable {
            region_id: region_id,
            to_peer_id: to_peer_id,
        })
    }
}

#[derive(Clone)]
pub struct ServerRaftStoreRouter {
    pub ch: SendCh<StoreMsg>,
}

impl ServerRaftStoreRouter {
    pub fn new(ch: SendCh<StoreMsg>) -> ServerRaftStoreRouter {
        ServerRaftStoreRouter { ch: ch }
    }
}

impl RaftStoreRouter for ServerRaftStoreRouter {
    fn try_send(&self, msg: StoreMsg) -> RaftStoreResult<()> {
        try!(self.ch.try_send(msg));
        Ok(())
    }

    fn send(&self, msg: StoreMsg) -> RaftStoreResult<()> {
        try!(self.ch.send(msg));
        Ok(())
    }

    fn send_raft_msg(&self, msg: RaftMessage) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::RaftMessage(msg))
    }

    fn send_command(&self, req: RaftCmdRequest, cb: Callback) -> RaftStoreResult<()> {
        self.try_send(StoreMsg::new_raft_cmd(req, cb))
    }

    fn report_unreachable(&self,
                          region_id: u64,
                          to_peer_id: u64,
                          to_store_id: u64)
                          -> RaftStoreResult<()> {
        let store = to_store_id.to_string();
        REPORT_FAILURE_MSG_COUNTER.with_label_values(&["unreachable", &*store]).inc();
        self.try_send(StoreMsg::ReportUnreachable {
            region_id: region_id,
            to_peer_id: to_peer_id,
        })
    }
}

pub struct ServerTransport<T, S>
    where T: RaftStoreRouter + 'static,
          S: StoreAddrResolver + Send + 'static
{
    raft_client: Arc<RwLock<RaftClient>>,
    snap_scheduler: Scheduler<SnapTask>,
    raft_router: T,
    snapshot_status_sender: Sender<SnapshotStatusMsg>,
    resolving: Arc<RwLock<HashSet<u64>>>,
    resolver: Arc<Mutex<S>>,
}

impl<T, S> Clone for ServerTransport<T, S>
    where T: RaftStoreRouter + 'static,
          S: StoreAddrResolver + Send + 'static
{
    fn clone(&self) -> Self {
        ServerTransport {
            raft_client: self.raft_client.clone(),
            snap_scheduler: self.snap_scheduler.clone(),
            raft_router: self.raft_router.clone(),
            snapshot_status_sender: self.snapshot_status_sender.clone(),
            resolving: self.resolving.clone(),
            resolver: self.resolver.clone(),
        }
    }
}

impl<T: RaftStoreRouter + 'static, S: StoreAddrResolver + Send + 'static> ServerTransport<T, S> {
    pub fn new(raft_client: Arc<RwLock<RaftClient>>,
               snap_scheduler: Scheduler<SnapTask>,
               raft_router: T,
               snapshot_status_sender: Sender<SnapshotStatusMsg>,
               resolver: S)
               -> ServerTransport<T, S> {
        ServerTransport {
            raft_client: raft_client,
            snap_scheduler: snap_scheduler,
            raft_router: raft_router,
            snapshot_status_sender: snapshot_status_sender,
            resolving: Arc::new(RwLock::new(Default::default())),
            resolver: Arc::new(Mutex::new(resolver)),
        }
    }

    fn send_store(&self, store_id: u64, msg: RaftMessage) {
        // check the corresponding token for store.
        let addr = self.raft_client.rl().addrs.get(&store_id).cloned();
        if let Some(addr) = addr {
            self.write_data(store_id, addr, msg);
            return;
        }

        // No connection, try to resolve it.
        if self.resolving.rl().contains(&store_id) {
            RESOLVE_STORE_COUNTER.with_label_values(&["resolving"]).inc();
            // If we are resolving the address, drop the message here.
            debug!("store {} address is being resolved, drop msg {:?}",
                   store_id,
                   msg);
            self.report_unreachable(msg);
            return;
        }

        debug!("begin to resolve store {} address", store_id);
        RESOLVE_STORE_COUNTER.with_label_values(&["resolve"]).inc();

        self.resolving.wl().insert(store_id);
        self.resolve(store_id, msg);
    }

    fn resolve(&self, store_id: u64, msg: RaftMessage) {
        let trans = self.clone();
        let cb = box move |addr| {
            // clear resolving.
            trans.resolving.wl().remove(&store_id);

            if let Err(e) = addr {
                RESOLVE_STORE_COUNTER.with_label_values(&["failed"]).inc();
                debug!("resolve store {} address failed {:?}", store_id, e);
                trans.report_unreachable(msg);
                return;
            }

            RESOLVE_STORE_COUNTER.with_label_values(&["success"]).inc();
            let addr = addr.unwrap();
            info!("resolve store {} address ok, addr {}", store_id, addr);
            trans.raft_client.wl().addrs.insert(store_id, addr);
            trans.write_data(store_id, addr, msg);
            // There may be no messages in the near future, so flush it immediately.
            trans.raft_client.wl().flush();
        };
        if let Err(e) = self.resolver.lock().unwrap().resolve(store_id, cb) {
            error!("try to resolve err {:?}", e);
        }
    }

    fn write_data(&self, store_id: u64, addr: SocketAddr, msg: RaftMessage) {
        if msg.get_message().has_snapshot() {
            return self.send_snapshot_sock(addr, msg);
        }
        if let Err(e) = self.raft_client.wl().send(store_id, addr, msg) {
            error!("send raft msg err {:?}", e);
        }
    }

    fn send_snapshot_sock(&self, sock_addr: SocketAddr, msg: RaftMessage) {
        let rep = self.new_snapshot_reporter(&msg);
        let cb = box move |res: Result<()>| {
            if res.is_err() {
                rep.report(SnapshotStatus::Failure);
            } else {
                rep.report(SnapshotStatus::Finish);
            }
        };
        if let Err(Stopped(SnapTask::SendTo { cb, .. })) = self.snap_scheduler
            .schedule(SnapTask::SendTo {
                addr: sock_addr,
                msg: msg,
                cb: cb,
            }) {
            error!("channel is closed, failed to schedule snapshot to {}",
                   sock_addr);
            cb(Err(box_err!("failed to schedule snapshot")));
        }
    }

    fn new_snapshot_reporter(&self, msg: &RaftMessage) -> SnapshotReporter {
        let region_id = msg.get_region_id();
        let to_peer_id = msg.get_to_peer().get_id();
        let to_store_id = msg.get_to_peer().get_store_id();

        SnapshotReporter {
            snapshot_status_sender: self.snapshot_status_sender.clone(),
            region_id: region_id,
            to_peer_id: to_peer_id,
            to_store_id: to_store_id,
        }
    }

    pub fn report_unreachable(&self, msg: RaftMessage) {
        let region_id = msg.get_region_id();
        let to_peer_id = msg.get_to_peer().get_id();
        let to_store_id = msg.get_to_peer().get_store_id();

        if let Err(e) = self.raft_router.report_unreachable(region_id, to_peer_id, to_store_id) {
            error!("report peer {} unreachable for region {} failed {:?}",
                   to_peer_id,
                   region_id,
                   e);
        }
    }

    pub fn flush_raft_client(&mut self) {
        self.raft_client.wl().flush();
    }
}

impl<T, S> Transport for ServerTransport<T, S>
    where T: RaftStoreRouter + 'static,
          S: StoreAddrResolver + Send + 'static
{
    fn send(&self, msg: RaftMessage) -> RaftStoreResult<()> {
        let to_store_id = msg.get_to_peer().get_store_id();
        self.send_store(to_store_id, msg);
        Ok(())
    }

    fn flush(&mut self) {
        self.flush_raft_client();
    }
}

struct SnapshotReporter {
    snapshot_status_sender: Sender<SnapshotStatusMsg>,
    region_id: u64,
    to_peer_id: u64,
    to_store_id: u64,
}

impl SnapshotReporter {
    pub fn report(&self, status: SnapshotStatus) {
        debug!("send snapshot to {} for {} {:?}",
               self.to_peer_id,
               self.region_id,
               status);

        if status == SnapshotStatus::Failure {
            let store = self.to_store_id.to_string();
            REPORT_FAILURE_MSG_COUNTER.with_label_values(&["snapshot", &*store]).inc();
        };

        if let Err(e) = self.snapshot_status_sender.send(SnapshotStatusMsg {
            region_id: self.region_id,
            to_peer_id: self.to_peer_id,
            status: status,
        }) {
            error!("report snapshot to peer {} in store {} with region {} err {:?}",
                   self.to_peer_id,
                   self.to_store_id,
                   self.region_id,
                   e);
        }
    }
}
<|endoftext|>


<commit_before>use cranelift_module::*;
use crate::prelude::*;
use rustc::mir::interpret::{read_target_uint, AllocId, AllocType, ConstValue, GlobalId};
use rustc::ty::Const;
use rustc_mir::interpret::{CompileTimeEvaluator, Memory};
use syntax::ast::Mutability as AstMutability;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        for data_id in self.done.drain() {
            module.finalize_data(data_id);
        }
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        TypeVariants::TyBool => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyUint(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyInt(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        TypeVariants::TyFnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(Instance::new(def_id, substs));
            CValue::Func(func_ref, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    let alloc = fx.tcx.const_value_to_allocation(const_);
    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<B: Backend>(tcx: TyCtxt, module: &mut Module<B>, def_id: DefId) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    module
        .declare_data(&*symbol_name, Linkage::Export, false)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(types::I64, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    CPlace::Addr(global_ptr, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<CompileTimeEvaluator>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(
            alloc.bytes.to_vec().into_boxed_slice(),
            match alloc.runtime_mutability {
                AstMutability::Mutable => Writability::Writable,
                AstMutability::Immutable => Writability::Readonly,
            },
        );

        for &(offset, reloc) in alloc.relocations.iter() {
            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Function(_) => unimplemented!("function static reference"),
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let reloc_offset = {
                let endianness = memory.endianness();
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}
<commit_msg>Fix trait method calls<commit_after>use cranelift_module::*;
use crate::prelude::*;
use rustc::mir::interpret::{read_target_uint, AllocId, AllocType, ConstValue, GlobalId};
use rustc::ty::Const;
use rustc_mir::interpret::{CompileTimeEvaluator, Memory};
use syntax::ast::Mutability as AstMutability;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        for data_id in self.done.drain() {
            module.finalize_data(data_id);
        }
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        TypeVariants::TyBool => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyUint(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        TypeVariants::TyInt(_) => {
            let bits = const_.val.to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        TypeVariants::TyFnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap());
            CValue::Func(func_ref, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    let alloc = fx.tcx.const_value_to_allocation(const_);
    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<B: Backend>(tcx: TyCtxt, module: &mut Module<B>, def_id: DefId) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    module
        .declare_data(&*symbol_name, Linkage::Export, false)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(types::I64, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    CPlace::Addr(global_ptr, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<CompileTimeEvaluator>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(
            alloc.bytes.to_vec().into_boxed_slice(),
            match alloc.runtime_mutability {
                AstMutability::Mutable => Writability::Writable,
                AstMutability::Immutable => Writability::Readonly,
            },
        );

        for &(offset, reloc) in alloc.relocations.iter() {
            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Function(_) => unimplemented!("function static reference"),
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let reloc_offset = {
                let endianness = memory.endianness();
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}
<|endoftext|>


<commit_before>use std::convert;
use std::io;
use std::result;
use std::num::FromPrimitive;
use std::str::Utf8Error;

use byteorder;

const FIXSTR_SIZE   : u8 = 0x1f;
const FIXARRAY_SIZE : u8 = 0x0f;
const FIXMAP_SIZE   : u8 = 0x0f;

enum Marker {
    PositiveFixnum(u8),
    NegativeFixnum(i8),
    Null,
    True,
    False,
    U8,
    U16,
    U32,
    U64,
    I8,
    I16,
    I32,
    I64,
    F32,
    F64,
    FixedString(u8),
    Str8,
    Str16,
    Str32,
    Bin8,
    Bin16,
    Bin32,
    FixedArray(u8),
    Array16,
    Array32,
    FixedMap(u8),
    Map16,
    Map32,
    FixExt1,
    FixExt2,
    FixExt4,
    FixExt8,
    FixExt16,
    Ext8,
    Ext16,
    Ext32,
}

impl FromPrimitive for Marker {
    fn from_i64(n: i64) -> Option<Marker> {
        FromPrimitive::from_u64(n as u64)
    }

    fn from_u64(n: u64) -> Option<Marker> {
        match n {
            val @ 0x00 ... 0x7f => Some(Marker::PositiveFixnum(val as u8)),
            val @ 0xe0 ... 0xff => Some(Marker::NegativeFixnum(val as i8)),
            val @ 0x80 ... 0x8f => Some(Marker::FixedMap((val as u8) & FIXMAP_SIZE)),
            val @ 0x90 ... 0x9f => Some(Marker::FixedArray((val as u8) & FIXARRAY_SIZE)),
            val @ 0xa0 ... 0xbf => Some(Marker::FixedString((val as u8) & FIXSTR_SIZE)),
            0xc0 => Some(Marker::Null),
            0xc1 => None, // Marked in MessagePack spec as never used.
            0xc2 => Some(Marker::False),
            0xc3 => Some(Marker::True),
            0xc4 => Some(Marker::Bin8),
            0xc5 => Some(Marker::Bin16),
            0xc6 => Some(Marker::Bin32),
            0xc7 => Some(Marker::Ext8),
            0xc8 => Some(Marker::Ext16),
            0xc9 => Some(Marker::Ext32),
            0xca => Some(Marker::F32),
            0xcb => Some(Marker::F64),
            0xcc => Some(Marker::U8),
            0xcd => Some(Marker::U16),
            0xce => Some(Marker::U32),
            0xcf => Some(Marker::U64),
            0xd0 => Some(Marker::I8),
            0xd1 => Some(Marker::I16),
            0xd2 => Some(Marker::I32),
            0xd3 => Some(Marker::I64),
            0xd4 => Some(Marker::FixExt1),
            0xd5 => Some(Marker::FixExt2),
            0xd6 => Some(Marker::FixExt4),
            0xd7 => Some(Marker::FixExt8),
            0xd8 => Some(Marker::FixExt16),
            0xd9 => Some(Marker::Str8),
            0xda => Some(Marker::Str16),
            0xdb => Some(Marker::Str32),
            0xdc => Some(Marker::Array16),
            0xdd => Some(Marker::Array32),
            0xde => Some(Marker::Map16),
            0xdf => Some(Marker::Map32),
            _ => None,
        }
    }
}

/// An error type for reading bytes from the reader.
///
/// This is a thin wrapper over the standard `io::Error` type. Namely, it adds one additional error
/// case: an unexpected EOF.
#[unstable(reason = "remove Debug trait")]
#[derive(Debug)]
pub enum ReadError {
    UnexpectedEOF,
    IO(io::Error),
}

// TODO: This is a hack, because io::Error has PartialEq sometimes.
impl PartialEq for ReadError {
    fn eq(&self, other: &ReadError) -> bool {
        match (self, other) {
            (&ReadError::UnexpectedEOF, &ReadError::UnexpectedEOF) => true,
            (&ReadError::IO(ref lhs),   &ReadError::IO(ref rhs)) => {
                lhs.kind() == rhs.kind()
            }
            _ => false
        }
    }

    fn ne(&self, other: &ReadError) -> bool {
        return !self.eq(other);
    }
}

impl convert::From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError { ReadError::IO(err) }
}

impl convert::From<ReadError> for io::Error {
    fn from(err: ReadError) -> io::Error {
        match err {
            ReadError::IO(err) => err,
            ReadError::UnexpectedEOF => io::Error::new(io::ErrorKind::Other, "unexpected EOF")
        }
    }
}

impl convert::From<byteorder::Error> for ReadError {
    fn from(err: byteorder::Error) -> ReadError {
        match err {
            byteorder::Error::UnexpectedEOF => ReadError::UnexpectedEOF,
            byteorder::Error::Io(err) => ReadError::IO(err),
        }
    }
}

#[unstable(reason = "remove Debug trait")]
#[derive(Debug, PartialEq)]
pub enum MarkerError {
    TypeMismatch, // TODO: Consider saving actual marker.
    Unexpected(u8),
}

#[unstable(reason = "may be set &[u8] in some errors, utf8 for example; remove Debug trait")]
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidMarker(MarkerError),     // Marker type error.
    InvalidMarkerRead(ReadError),   // IO error while reading marker.
    InvalidDataRead(ReadError),     // IO error while reading data.
    // TODO: These errors only used in functions with data copy (str, bin, ext). Maybe we need another error enum for them?
    BufferSizeTooSmall(u32),        // Too small buffer provided to copy all the data.
    InvalidDataCopy(u32, ReadError),    // The string, binary or ext has been read partially.
    InvalidUtf8(u32, Utf8Error),    // Invalid UTF8 sequence.
}

#[unstable(reason = "Core? Shit name!")]
#[derive(Debug, PartialEq)]
pub enum DecodeStringError<'a> {
    Core(Error),
    InvalidDataCopy(&'a [u8], ReadError),
    InvalidUtf8(&'a [u8], Utf8Error),
}

impl<'a> convert::From<Error> for DecodeStringError<'a> {
    fn from(err: Error) -> DecodeStringError<'a> {
        DecodeStringError::Core(err)
    }
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Debug, PartialEq)]
pub enum Integer {
    U64(u64),
    I64(i64),
}

pub enum Float {
    F32(f32),
    F64(f64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Null,
    Integer(Integer),
    String(String),
}

pub mod decode;
<commit_msg>[Doc] More docs.<commit_after>use std::convert;
use std::io;
use std::result;
use std::num::FromPrimitive;
use std::str::Utf8Error;

use byteorder;

const FIXSTR_SIZE   : u8 = 0x1f;
const FIXARRAY_SIZE : u8 = 0x0f;
const FIXMAP_SIZE   : u8 = 0x0f;

enum Marker {
    PositiveFixnum(u8),
    NegativeFixnum(i8),
    Null,
    True,
    False,
    U8,
    U16,
    U32,
    U64,
    I8,
    I16,
    I32,
    I64,
    F32,
    F64,
    FixedString(u8),
    Str8,
    Str16,
    Str32,
    Bin8,
    Bin16,
    Bin32,
    FixedArray(u8),
    Array16,
    Array32,
    FixedMap(u8),
    Map16,
    Map32,
    FixExt1,
    FixExt2,
    FixExt4,
    FixExt8,
    FixExt16,
    Ext8,
    Ext16,
    Ext32,
}

impl FromPrimitive for Marker {
    fn from_i64(n: i64) -> Option<Marker> {
        FromPrimitive::from_u64(n as u64)
    }

    fn from_u64(n: u64) -> Option<Marker> {
        match n {
            val @ 0x00 ... 0x7f => Some(Marker::PositiveFixnum(val as u8)),
            val @ 0xe0 ... 0xff => Some(Marker::NegativeFixnum(val as i8)),
            val @ 0x80 ... 0x8f => Some(Marker::FixedMap((val as u8) & FIXMAP_SIZE)),
            val @ 0x90 ... 0x9f => Some(Marker::FixedArray((val as u8) & FIXARRAY_SIZE)),
            val @ 0xa0 ... 0xbf => Some(Marker::FixedString((val as u8) & FIXSTR_SIZE)),
            0xc0 => Some(Marker::Null),
            0xc1 => None, // Marked in MessagePack spec as never used.
            0xc2 => Some(Marker::False),
            0xc3 => Some(Marker::True),
            0xc4 => Some(Marker::Bin8),
            0xc5 => Some(Marker::Bin16),
            0xc6 => Some(Marker::Bin32),
            0xc7 => Some(Marker::Ext8),
            0xc8 => Some(Marker::Ext16),
            0xc9 => Some(Marker::Ext32),
            0xca => Some(Marker::F32),
            0xcb => Some(Marker::F64),
            0xcc => Some(Marker::U8),
            0xcd => Some(Marker::U16),
            0xce => Some(Marker::U32),
            0xcf => Some(Marker::U64),
            0xd0 => Some(Marker::I8),
            0xd1 => Some(Marker::I16),
            0xd2 => Some(Marker::I32),
            0xd3 => Some(Marker::I64),
            0xd4 => Some(Marker::FixExt1),
            0xd5 => Some(Marker::FixExt2),
            0xd6 => Some(Marker::FixExt4),
            0xd7 => Some(Marker::FixExt8),
            0xd8 => Some(Marker::FixExt16),
            0xd9 => Some(Marker::Str8),
            0xda => Some(Marker::Str16),
            0xdb => Some(Marker::Str32),
            0xdc => Some(Marker::Array16),
            0xdd => Some(Marker::Array32),
            0xde => Some(Marker::Map16),
            0xdf => Some(Marker::Map32),
            _ => None,
        }
    }
}

/// An error type for reading bytes from the reader.
///
/// This is a thin wrapper over the standard `io::Error` type. Namely, it adds one additional error
/// case: an unexpected EOF.
#[unstable(reason = "remove Debug trait")]
#[derive(Debug)]
pub enum ReadError {
    UnexpectedEOF,
    IO(io::Error),
}

// TODO: This is a hack, because io::Error has PartialEq sometimes.
impl PartialEq for ReadError {
    fn eq(&self, other: &ReadError) -> bool {
        match (self, other) {
            (&ReadError::UnexpectedEOF, &ReadError::UnexpectedEOF) => true,
            (&ReadError::IO(ref lhs),   &ReadError::IO(ref rhs)) => {
                lhs.kind() == rhs.kind()
            }
            _ => false
        }
    }

    fn ne(&self, other: &ReadError) -> bool {
        return !self.eq(other);
    }
}

impl convert::From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError { ReadError::IO(err) }
}

impl convert::From<ReadError> for io::Error {
    fn from(err: ReadError) -> io::Error {
        match err {
            ReadError::IO(err) => err,
            ReadError::UnexpectedEOF => io::Error::new(io::ErrorKind::Other, "unexpected EOF")
        }
    }
}

impl convert::From<byteorder::Error> for ReadError {
    fn from(err: byteorder::Error) -> ReadError {
        match err {
            byteorder::Error::UnexpectedEOF => ReadError::UnexpectedEOF,
            byteorder::Error::Io(err) => ReadError::IO(err),
        }
    }
}

#[unstable(reason = "remove Debug trait")]
#[derive(Debug, PartialEq)]
pub enum MarkerError {
    TypeMismatch, // TODO: Consider saving actual marker.
    Unexpected(u8),
}

#[unstable(reason = "may be set &[u8] in some errors, utf8 for example; remove Debug trait")]
#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidMarker(MarkerError),     // Marker type error.
    InvalidMarkerRead(ReadError),   // IO error while reading marker.
    InvalidDataRead(ReadError),     // IO error while reading data.
    // TODO: These errors only used in functions with data copy (str, bin, ext). Maybe we need another error enum for them?
    BufferSizeTooSmall(u32),        // Too small buffer provided to copy all the data.
    InvalidDataCopy(u32, ReadError),    // The string, binary or ext has been read partially.
    InvalidUtf8(u32, Utf8Error),    // Invalid UTF8 sequence.
}

#[unstable(reason = "Core? Shit name!")]
#[derive(Debug, PartialEq)]
pub enum DecodeStringError<'a> {
    Core(Error),
    InvalidDataCopy(&'a [u8], ReadError),
    InvalidUtf8(&'a [u8], Utf8Error),
}

impl<'a> convert::From<Error> for DecodeStringError<'a> {
    fn from(err: Error) -> DecodeStringError<'a> {
        DecodeStringError::Core(err)
    }
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Debug, PartialEq)]
pub enum Integer {
    /// Every non-negative integer is treated as u64, even if it fits in i64.
    U64(u64),
    /// Every negative integer is treated as i64.
    I64(i64),
}

pub enum Float {
    F32(f32),
    F64(f64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Null,
    Integer(Integer),
    String(String),
}

pub mod decode;
<|endoftext|>


<commit_before>use std::io::{self, Write};

use futures::{future, Async, Future, Poll, Sink, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};

use termion::event::{Event, Key};
use tokio::run;
use xrl::{AvailablePlugins, Client, ConfigChanged, Frontend, FrontendBuilder,
          PluginStarted, PluginStoped, ScrollTo, ServerResult, Style, ThemeChanged, Update,
          UpdateCmds};

use xdg::BaseDirectories;
use failure::Error;

use core::{Terminal, TerminalEvent, Command};
use widgets::{Editor, CommandPrompt};

pub struct Tui {
    pub editor: Editor,
    pub prompt: Option<CommandPrompt>,
    pub term: Terminal,
    pub term_size: (u16, u16),
    pub shutdown: bool,
}

impl Tui {
    pub fn new(
        mut client: Client,
        events: UnboundedReceiver<CoreEvent>,
    ) -> Result<Self, Error> {

        let conf_dir = BaseDirectories::with_prefix("xi")
            .ok()
            .and_then(|dirs| Some(dirs.get_config_home().to_string_lossy().into_owned()));
        run(
            client
                .client_started(conf_dir.as_ref().map(|dir| &**dir), None)
                .map_err(|_| ()),
        );

        Ok(Tui {
            term: Terminal::new()?,
            shutdown: false,
            term_size: (0, 0),
            editor: Editor::new(client, events),
            prompt: None,
        })
    }

    fn handle_resize(&mut self, size: (u16, u16)) {
        self.term_size = size;
        self.editor.handle_resize(size);
    }

    fn exit(&mut self) {
        self.shutdown = true;
    }

    pub fn handle_cmd(&mut self, cmd: Command) {
        match cmd {
            Command::Cancel => {
                self.prompt = None;
            },
            Command::Quit => self.exit(),
            Command::Save(view) => self.editor.save(view),
            Command::Invalid(cmd) => {
                error!("Received invalid editor command: {}", cmd);
            }
        }
    }

    /// Global keybindings can be parsed here
    fn handle_input(&mut self, event: Event) {
        match event {
            Event::Key(Key::Ctrl('c')) => self.exit(),
            Event::Key(Key::Char(':')) => {
                if let Some(ref mut prompt) = self.prompt {
                    prompt.handle_input(event);
                } else {
                    self.prompt = Some(CommandPrompt::default());
                }
            },
            event => {
                let mut out = None;
                if let Some(ref mut prompt) = self.prompt {
                    if let Some(cmd) = prompt.handle_input(event) {
                        out = Some(cmd);
                    }
                } else {
                    self.editor.handle_input(event);
                }
                if let Some(out) = out {
                    self.handle_cmd(out);
                    self.prompt = None;
                }
            }
        }
    }

    /// Check and handle terminal events.
    fn process_terminal_events(&mut self) {
        let mut new_size: Option<(u16, u16)> = None;
        loop {
            match self.term.poll() {
                 Ok(Async::Ready(Some(event))) => match event {
                    TerminalEvent::Resize(size) => {
                        new_size = Some(size);
                    }
                    TerminalEvent::Input(input) => self.handle_input(input),
                },
                Ok(Async::Ready(None)) => {
                    error!("terminal stream shut down => exiting");
                    self.shutdown = true;
                }
                Ok(Async::NotReady) => break,
                Err(_) => {
                    error!("error while polling terminal stream => exiting");
                    self.shutdown = true;
                }
            }
        }
        if let Some(size) = new_size {
            if !self.shutdown {
                self.handle_resize(size);
            }
        }
    }

    fn render(&mut self) -> Result<(), Error> {
        if let Some(ref mut prompt) = self.prompt {
            prompt.render(self.term.stdout(), self.term_size.1)?;
        } else {
            self.editor.render(self.term.stdout())?;
        }
        if let Err(e) = self.term.stdout().flush() {
            error!("failed to flush stdout: {}", e);
        }
        Ok(())
    }
}

#[derive(Debug)]
pub enum CoreEvent {
    Update(Update),
    ScrollTo(ScrollTo),
    SetStyle(Style),
}

impl Future for Tui {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.editor.process_open_requests();
        self.editor.process_delayed_events();
        self.process_terminal_events();
        self.editor.process_core_events();

        if let Err(e) = self.render() {
            error!("error: {}", e);
            error!("caused by: {}", e.cause());
        }

        if self.shutdown {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

/// Actual frontend that implementes `xrl::Frontend`
/// It's future is the main loop of xi-term.
pub struct TuiService(UnboundedSender<CoreEvent>);

impl TuiService {
    fn send_core_event(&mut self, event: CoreEvent) -> ServerResult<()> {
        if let Err(e) = self.0.start_send(event) {
            let e = format!("failed to send core event to TUI: {}", e);
            error!("{}", e);
            return Box::new(future::err(e.into()));
        }
        match self.0.poll_complete() {
            Ok(_) => Box::new(future::ok(())),
            Err(e) => {
                let e = format!("failed to send core event to TUI: {}", e);
                Box::new(future::err(e.into()))
            }
        }
    }
}

impl Frontend for TuiService {
    fn update(&mut self, update: Update) -> ServerResult<()> {
        self.send_core_event(CoreEvent::Update(update))
    }

    fn scroll_to(&mut self, scroll_to: ScrollTo) -> ServerResult<()> {
        self.send_core_event(CoreEvent::ScrollTo(scroll_to))
    }

    fn def_style(&mut self, style: Style) -> ServerResult<()> {
        self.send_core_event(CoreEvent::SetStyle(style))
    }
    fn available_plugins(&mut self, _plugins: AvailablePlugins) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn update_cmds(&mut self, _plugins: UpdateCmds) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn plugin_started(&mut self, _plugins: PluginStarted) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn plugin_stoped(&mut self, _plugin: PluginStoped) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn config_changed(&mut self, _config: ConfigChanged) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn theme_changed(&mut self, _theme: ThemeChanged) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
}

pub struct TuiServiceBuilder(UnboundedSender<CoreEvent>);

impl TuiServiceBuilder {
    pub fn new() -> (Self, UnboundedReceiver<CoreEvent>) {
        let (tx, rx) = unbounded();
        (TuiServiceBuilder(tx), rx)
    }
}

impl FrontendBuilder<TuiService> for TuiServiceBuilder {
    fn build(self, _client: Client) -> TuiService {
        TuiService(self.0)
    }
}
<commit_msg>change open prompt command to ^:<commit_after>use std::io::{self, Write};

use futures::{future, Async, Future, Poll, Sink, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};

use termion::event::{Event, Key};
use tokio::run;
use xrl::{AvailablePlugins, Client, ConfigChanged, Frontend, FrontendBuilder,
          PluginStarted, PluginStoped, ScrollTo, ServerResult, Style, ThemeChanged, Update,
          UpdateCmds};

use xdg::BaseDirectories;
use failure::Error;

use core::{Terminal, TerminalEvent, Command};
use widgets::{Editor, CommandPrompt};

pub struct Tui {
    pub editor: Editor,
    pub prompt: Option<CommandPrompt>,
    pub term: Terminal,
    pub term_size: (u16, u16),
    pub shutdown: bool,
}

impl Tui {
    pub fn new(
        mut client: Client,
        events: UnboundedReceiver<CoreEvent>,
    ) -> Result<Self, Error> {

        let conf_dir = BaseDirectories::with_prefix("xi")
            .ok()
            .and_then(|dirs| Some(dirs.get_config_home().to_string_lossy().into_owned()));
        run(
            client
                .client_started(conf_dir.as_ref().map(|dir| &**dir), None)
                .map_err(|_| ()),
        );

        Ok(Tui {
            term: Terminal::new()?,
            shutdown: false,
            term_size: (0, 0),
            editor: Editor::new(client, events),
            prompt: None,
        })
    }

    fn handle_resize(&mut self, size: (u16, u16)) {
        self.term_size = size;
        self.editor.handle_resize(size);
    }

    fn exit(&mut self) {
        self.shutdown = true;
    }

    pub fn handle_cmd(&mut self, cmd: Command) {
        match cmd {
            Command::Cancel => {
                self.prompt = None;
            },
            Command::Quit => self.exit(),
            Command::Save(view) => self.editor.save(view),
            Command::Invalid(cmd) => {
                error!("Received invalid editor command: {}", cmd);
            }
        }
    }

    /// Global keybindings can be parsed here
    fn handle_input(&mut self, event: Event) {
        match event {
            Event::Key(Key::Ctrl('c')) => self.exit(),
            Event::Key(Key::Ctrl(':')) => {
                if let Some(ref mut prompt) = self.prompt {
                    prompt.handle_input(event);
                } else {
                    self.prompt = Some(CommandPrompt::default());
                }
            },
            event => {
                let mut out = None;
                if let Some(ref mut prompt) = self.prompt {
                    if let Some(cmd) = prompt.handle_input(event) {
                        out = Some(cmd);
                    }
                } else {
                    self.editor.handle_input(event);
                }
                if let Some(out) = out {
                    self.handle_cmd(out);
                    self.prompt = None;
                }
            }
        }
    }

    /// Check and handle terminal events.
    fn process_terminal_events(&mut self) {
        let mut new_size: Option<(u16, u16)> = None;
        loop {
            match self.term.poll() {
                 Ok(Async::Ready(Some(event))) => match event {
                    TerminalEvent::Resize(size) => {
                        new_size = Some(size);
                    }
                    TerminalEvent::Input(input) => self.handle_input(input),
                },
                Ok(Async::Ready(None)) => {
                    error!("terminal stream shut down => exiting");
                    self.shutdown = true;
                }
                Ok(Async::NotReady) => break,
                Err(_) => {
                    error!("error while polling terminal stream => exiting");
                    self.shutdown = true;
                }
            }
        }
        if let Some(size) = new_size {
            if !self.shutdown {
                self.handle_resize(size);
            }
        }
    }

    fn render(&mut self) -> Result<(), Error> {
        if let Some(ref mut prompt) = self.prompt {
            prompt.render(self.term.stdout(), self.term_size.1)?;
        } else {
            self.editor.render(self.term.stdout())?;
        }
        if let Err(e) = self.term.stdout().flush() {
            error!("failed to flush stdout: {}", e);
        }
        Ok(())
    }
}

#[derive(Debug)]
pub enum CoreEvent {
    Update(Update),
    ScrollTo(ScrollTo),
    SetStyle(Style),
}

impl Future for Tui {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.editor.process_open_requests();
        self.editor.process_delayed_events();
        self.process_terminal_events();
        self.editor.process_core_events();

        if let Err(e) = self.render() {
            error!("error: {}", e);
            error!("caused by: {}", e.cause());
        }

        if self.shutdown {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

/// Actual frontend that implementes `xrl::Frontend`
/// It's future is the main loop of xi-term.
pub struct TuiService(UnboundedSender<CoreEvent>);

impl TuiService {
    fn send_core_event(&mut self, event: CoreEvent) -> ServerResult<()> {
        if let Err(e) = self.0.start_send(event) {
            let e = format!("failed to send core event to TUI: {}", e);
            error!("{}", e);
            return Box::new(future::err(e.into()));
        }
        match self.0.poll_complete() {
            Ok(_) => Box::new(future::ok(())),
            Err(e) => {
                let e = format!("failed to send core event to TUI: {}", e);
                Box::new(future::err(e.into()))
            }
        }
    }
}

impl Frontend for TuiService {
    fn update(&mut self, update: Update) -> ServerResult<()> {
        self.send_core_event(CoreEvent::Update(update))
    }

    fn scroll_to(&mut self, scroll_to: ScrollTo) -> ServerResult<()> {
        self.send_core_event(CoreEvent::ScrollTo(scroll_to))
    }

    fn def_style(&mut self, style: Style) -> ServerResult<()> {
        self.send_core_event(CoreEvent::SetStyle(style))
    }
    fn available_plugins(&mut self, _plugins: AvailablePlugins) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn update_cmds(&mut self, _plugins: UpdateCmds) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn plugin_started(&mut self, _plugins: PluginStarted) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn plugin_stoped(&mut self, _plugin: PluginStoped) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn config_changed(&mut self, _config: ConfigChanged) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
    fn theme_changed(&mut self, _theme: ThemeChanged) -> ServerResult<()> {
        Box::new(future::ok(()))
    }
}

pub struct TuiServiceBuilder(UnboundedSender<CoreEvent>);

impl TuiServiceBuilder {
    pub fn new() -> (Self, UnboundedReceiver<CoreEvent>) {
        let (tx, rx) = unbounded();
        (TuiServiceBuilder(tx), rx)
    }
}

impl FrontendBuilder<TuiService> for TuiServiceBuilder {
    fn build(self, _client: Client) -> TuiService {
        TuiService(self.0)
    }
}
<|endoftext|>


<commit_before>//! `ndarray` compability

use std::ops::Range;
use super::{FitsFile, FitsHdu};
use super::fitsfile::ReadImage;
use super::errors::Result;
use super::types::HduInfo;
use ndarray::{Array, ArrayD};

impl<T> ReadImage for ArrayD<T>
where
    T: Clone,
    Vec<T>: ReadImage,
{
    fn read_section(
        _fits_file: &mut FitsFile,
        _hdu: &FitsHdu,
        _range: Range<usize>,
    ) -> Result<Self> {
        unimplemented!()
    }

    fn read_rows(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        start_row: usize,
        num_rows: usize,
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_rows(fits_file, hdu, start_row, num_rows)?;
        let arr = Array::from_vec(data);
        let row_length = arr.len() / num_rows;
        Ok(arr.into_shape(vec![num_rows, row_length]).unwrap())
    }

    fn read_row(fits_file: &mut FitsFile, hdu: &FitsHdu, row: usize) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_row(fits_file, hdu, row)?;
        let shape = vec![data.len()];
        Ok(Array::from_shape_vec(shape, data).unwrap())
    }

    fn read_region(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        ranges: &[&Range<usize>],
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_region(fits_file, hdu, ranges)?;
        let shape: Vec<usize> = (0..ranges.len())
            .map(|i| ranges[i].end - ranges[i].start)
            .collect();
        let arr = Array::from_shape_vec(shape, data).unwrap();
        Ok(arr)
    }

    fn read_image(fits_file: &mut FitsFile, hdu: &FitsHdu) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                let data: Vec<T> = ReadImage::read_image(fits_file, hdu)?;
                let shape: Vec<usize> = (0..2).map(|i| shape[i]).collect();
                let arr = Array::from_shape_vec(shape, data).unwrap();
                Ok(arr)
            }
            _ => unreachable!(),
        }
    }
}

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

    #[test]
    fn test_read_image() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
        let dim = data.dim();
        assert_eq!(dim[0], 100);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[20, 5]], 152);
    }

    #[test]
    fn test_read_rows() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
        let dim = data.dim();
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[1, 52]], 184);
    }

    #[test]
    fn test_read_row() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
        assert_eq!(data[20], 156);
    }

    #[test]
    fn test_read_region() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
        let dim = data.dim();
        assert_eq!(dim[0], 10);
        assert_eq!(dim[1], 30);
        assert_eq!(data[[5, 10]], 160);
    }
}
<commit_msg>Implement read_section<commit_after>//! `ndarray` compability

use std::ops::Range;
use super::{FitsFile, FitsHdu};
use super::fitsfile::ReadImage;
use super::errors::Result;
use super::types::HduInfo;
use ndarray::{Array, ArrayD};

impl<T> ReadImage for ArrayD<T>
where
    T: Clone,
    Vec<T>: ReadImage,
{
    fn read_section(fits_file: &mut FitsFile, hdu: &FitsHdu, range: Range<usize>) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                if shape.len() != 2 {
                    return Err("Only 2D images supported for now".into());
                }

                let width = shape[1];

                if range.start % width != 0 {
                    return Err("range must start on row boundary".into());
                }
                let start_pixel = range.start / width;

                let n_pixels_requested = range.end - range.start;
                if n_pixels_requested % width != 0 {
                    return Err(
                        "must request number of pixels exactly divisible by image width".into(),
                    );
                }

                let n_rows = n_pixels_requested / width;
                ReadImage::read_rows(fits_file, hdu, start_pixel, n_rows)
            }
            HduInfo::TableInfo { .. } => {
                return Err("Cannot read image data from a FITS table".into())
            }
            _ => unreachable!(),
        }
    }

    fn read_rows(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        start_row: usize,
        num_rows: usize,
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_rows(fits_file, hdu, start_row, num_rows)?;
        let arr = Array::from_vec(data);
        let row_length = arr.len() / num_rows;
        Ok(arr.into_shape(vec![num_rows, row_length]).unwrap())
    }

    fn read_row(fits_file: &mut FitsFile, hdu: &FitsHdu, row: usize) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_row(fits_file, hdu, row)?;
        let shape = vec![data.len()];
        Ok(Array::from_shape_vec(shape, data).unwrap())
    }

    fn read_region(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        ranges: &[&Range<usize>],
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_region(fits_file, hdu, ranges)?;
        let shape: Vec<usize> = (0..ranges.len())
            .map(|i| ranges[i].end - ranges[i].start)
            .collect();
        let arr = Array::from_shape_vec(shape, data).unwrap();
        Ok(arr)
    }

    fn read_image(fits_file: &mut FitsFile, hdu: &FitsHdu) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                let data: Vec<T> = ReadImage::read_image(fits_file, hdu)?;
                let shape: Vec<usize> = (0..2).map(|i| shape[i]).collect();
                let arr = Array::from_shape_vec(shape, data).unwrap();
                Ok(arr)
            }
            _ => unreachable!(),
        }
    }
}

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

    #[test]
    fn test_read_image() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
        let dim = data.dim();
        assert_eq!(dim[0], 100);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[20, 5]], 152);
    }

    #[test]
    fn test_read_rows() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
        let dim = data.dim();
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[1, 52]], 184);
    }

    #[test]
    fn test_read_row() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
        assert_eq!(data[20], 156);
    }

    #[test]
    fn test_read_region() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
        let dim = data.dim();
        assert_eq!(dim[0], 10);
        assert_eq!(dim[1], 30);
        assert_eq!(data[[5, 10]], 160);
    }

    #[test]
    fn test_read_section() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        assert!(hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250).is_err());

        let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
        let dim = data.dim();
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[0, 10]], 160);
    }
}
<|endoftext|>