<commit_before>use std::fmt;
use std::io::prelude::*;

use atty;
use termcolor::Color::{Green, Red, Yellow, Cyan};
use termcolor::{self, StandardStream, Color, ColorSpec, WriteColor};

use util::errors::CargoResult;

/// The requested verbosity of output
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet
}

/// An abstraction around a `Write`able object that remembers preferences for output verbosity and
/// color.
pub struct Shell {
    /// the `Write`able object, either with or without color support (represented by different enum
    /// variants)
    err: ShellOut,
    /// How verbose messages should be
    verbosity: Verbosity,
}

impl fmt::Debug for Shell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match &self.err {
            &ShellOut::Write(_) => {
                f.debug_struct("Shell")
                    .field("verbosity", &self.verbosity)
                    .finish()
            }
            &ShellOut::Stream { color_choice, .. } => {
                f.debug_struct("Shell")
                    .field("verbosity", &self.verbosity)
                    .field("color_choice", &color_choice)
                    .finish()
            }
        }
    }
}

/// A `Write`able object, either with or without color support
enum ShellOut {
    /// A plain write object without color support
    Write(Box<Write>),
    /// Color-enabled stdio, with information on whether color should be used
    Stream {
        stream: StandardStream,
        tty: bool,
        color_choice: ColorChoice,
    },
}

/// Whether messages should use color output
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ColorChoice {
    /// Force color output
    Always,
    /// Force disable color output
    Never,
    /// Intelligently guess whether to use color output
    CargoAuto,
}

impl Shell {
    /// Create a new shell (color choice and verbosity), defaulting to 'auto' color and verbose
    /// output.
    pub fn new() -> Shell {
        Shell {
            err: ShellOut::Stream {
                stream: StandardStream::stderr(ColorChoice::CargoAuto.to_termcolor_color_choice()),
                color_choice: ColorChoice::CargoAuto,
                tty: atty::is(atty::Stream::Stderr),
            },
            verbosity: Verbosity::Verbose,
        }
    }

    /// Create a shell from a plain writable object, with no color, and max verbosity.
    pub fn from_write(out: Box<Write>) -> Shell {
        Shell {
            err: ShellOut::Write(out),
            verbosity: Verbosity::Verbose,
        }
    }

    /// Print a message, where the status will have `color` color, and can be justified. The
    /// messages follows without color.
    fn print(&mut self,
             status: &fmt::Display,
             message: Option<&fmt::Display>,
             color: Color,
             justified: bool) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => {
                self.err.print(status, message, color, justified)
            }
        }
    }

    /// Returns the width of the terminal in spaces, if any
    pub fn err_width(&self) -> Option<usize> {
        match self.err {
            ShellOut::Stream { tty: true, .. } => imp::stderr_width(),
            _ => None,
        }
    }

    /// Returns whether stderr is a tty
    pub fn is_err_tty(&self) -> bool {
        match self.err {
            ShellOut::Stream { tty, .. } => tty,
            _ => false,
        }
    }

    /// Get a reference to the underlying writer
    pub fn err(&mut self) -> &mut Write {
        self.err.as_write()
    }

    /// Shortcut to right-align and color green a status message.
    pub fn status<T, U>(&mut self, status: T, message: U) -> CargoResult<()>
        where T: fmt::Display, U: fmt::Display
    {
        self.print(&status, Some(&message), Green, true)
    }

    pub fn status_header<T>(&mut self, status: T) -> CargoResult<()>
        where T: fmt::Display,
    {
        self.print(&status, None, Cyan, true)
    }

    /// Shortcut to right-align a status message.
    pub fn status_with_color<T, U>(&mut self,
                                   status: T,
                                   message: U,
                                   color: Color) -> CargoResult<()>
        where T: fmt::Display, U: fmt::Display
    {
        self.print(&status, Some(&message), color, true)
    }

    /// Run the callback only if we are in verbose mode
    pub fn verbose<F>(&mut self, mut callback: F) -> CargoResult<()>
        where F: FnMut(&mut Shell) -> CargoResult<()>
    {
        match self.verbosity {
            Verbosity::Verbose => callback(self),
            _ => Ok(())
        }
    }

    /// Run the callback if we are not in verbose mode.
    pub fn concise<F>(&mut self, mut callback: F) -> CargoResult<()>
        where F: FnMut(&mut Shell) -> CargoResult<()>
    {
        match self.verbosity {
            Verbosity::Verbose => Ok(()),
            _ => callback(self)
        }
    }

    /// Print a red 'error' message
    pub fn error<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        self.print(&"error:", Some(&message), Red, false)
    }

    /// Print an amber 'warning' message
    pub fn warn<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => self.print(&"warning:", Some(&message), Yellow, false),
        }
    }

    /// Update the verbosity of the shell
    pub fn set_verbosity(&mut self, verbosity: Verbosity) {
        self.verbosity = verbosity;
    }

    /// Get the verbosity of the shell
    pub fn verbosity(&self) -> Verbosity {
        self.verbosity
    }

    /// Update the color choice (always, never, or auto) from a string.
    pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
        if let ShellOut::Stream { ref mut stream, ref mut color_choice, .. } =  self.err {
            let cfg = match color {
                Some("always") => ColorChoice::Always,
                Some("never") => ColorChoice::Never,

                Some("auto") |
                None => ColorChoice::CargoAuto,

                Some(arg) => bail!("argument for --color must be auto, always, or \
                                    never, but found `{}`", arg),
            };
            *color_choice = cfg;
            *stream = StandardStream::stderr(cfg.to_termcolor_color_choice());
        }
        Ok(())
    }

    /// Get the current color choice
    ///
    /// If we are not using a color stream, this will always return Never, even if the color choice
    /// has been set to something else.
    pub fn color_choice(&self) -> ColorChoice {
        match self.err {
            ShellOut::Stream { color_choice, .. } => color_choice,
            ShellOut::Write(_) => ColorChoice::Never,
        }
    }
}

impl ShellOut {
    /// Print out a message with a status. The status comes first and is bold + the given color.
    /// The status can be justified, in which case the max width that will right align is 12 chars.
    fn print(&mut self,
             status: &fmt::Display,
             message: Option<&fmt::Display>,
             color: Color,
             justified: bool) -> CargoResult<()> {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => {
                stream.reset()?;
                stream.set_color(ColorSpec::new()
                                    .set_bold(true)
                                    .set_fg(Some(color)))?;
                if justified {
                    write!(stream, "{:>12}", status)?;
                } else {
                    write!(stream, "{}", status)?;
                }
                stream.reset()?;
                match message {
                    Some(message) => write!(stream, " {}\n", message)?,
                    None => write!(stream, " ")?,
                }
            }
            ShellOut::Write(ref mut w) => {
                if justified {
                    write!(w, "{:>12}", status)?;
                } else {
                    write!(w, "{}", status)?;
                }
                match message {
                    Some(message) => write!(w, " {}\n", message)?,
                    None => write!(w, " ")?,
                }
            }
        }
        Ok(())
    }

    /// Get this object as a `io::Write`.
    fn as_write(&mut self) -> &mut Write {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => stream,
            ShellOut::Write(ref mut w) => w,
        }
    }
}

impl ColorChoice {
    /// Convert our color choice to termcolor's version
    fn to_termcolor_color_choice(&self) -> termcolor::ColorChoice {
        match *self {
            ColorChoice::Always => termcolor::ColorChoice::Always,
            ColorChoice::Never => termcolor::ColorChoice::Never,
            ColorChoice::CargoAuto => {
                if atty::is(atty::Stream::Stderr) {
                    termcolor::ColorChoice::Auto
                } else {
                    termcolor::ColorChoice::Never
                }
            }
        }
    }
}

#[cfg(unix)]
mod imp {
    use std::mem;

    use libc;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let mut winsize: libc::winsize = mem::zeroed();
            if libc::ioctl(libc::STDERR_FILENO, libc::TIOCGWINSZ, &mut winsize) < 0 {
                return None
            }
            if winsize.ws_col > 0 {
                Some(winsize.ws_col as usize)
            } else {
                None
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use std::mem;

    extern crate winapi;
    extern crate kernel32;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let stdout = kernel32::GetStdHandle(winapi::STD_ERROR_HANDLE);
            let mut csbi: winapi::CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
            if kernel32::GetConsoleScreenBufferInfo(stdout, &mut csbi) == 0 {
                return None
            }
            Some((csbi.srWindow.Right - csbi.srWindow.Left) as usize)
        }
    }
}
<commit_msg>Fix compilation on more platforms<commit_after>use std::fmt;
use std::io::prelude::*;

use atty;
use termcolor::Color::{Green, Red, Yellow, Cyan};
use termcolor::{self, StandardStream, Color, ColorSpec, WriteColor};

use util::errors::CargoResult;

/// The requested verbosity of output
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet
}

/// An abstraction around a `Write`able object that remembers preferences for output verbosity and
/// color.
pub struct Shell {
    /// the `Write`able object, either with or without color support (represented by different enum
    /// variants)
    err: ShellOut,
    /// How verbose messages should be
    verbosity: Verbosity,
}

impl fmt::Debug for Shell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match &self.err {
            &ShellOut::Write(_) => {
                f.debug_struct("Shell")
                    .field("verbosity", &self.verbosity)
                    .finish()
            }
            &ShellOut::Stream { color_choice, .. } => {
                f.debug_struct("Shell")
                    .field("verbosity", &self.verbosity)
                    .field("color_choice", &color_choice)
                    .finish()
            }
        }
    }
}

/// A `Write`able object, either with or without color support
enum ShellOut {
    /// A plain write object without color support
    Write(Box<Write>),
    /// Color-enabled stdio, with information on whether color should be used
    Stream {
        stream: StandardStream,
        tty: bool,
        color_choice: ColorChoice,
    },
}

/// Whether messages should use color output
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ColorChoice {
    /// Force color output
    Always,
    /// Force disable color output
    Never,
    /// Intelligently guess whether to use color output
    CargoAuto,
}

impl Shell {
    /// Create a new shell (color choice and verbosity), defaulting to 'auto' color and verbose
    /// output.
    pub fn new() -> Shell {
        Shell {
            err: ShellOut::Stream {
                stream: StandardStream::stderr(ColorChoice::CargoAuto.to_termcolor_color_choice()),
                color_choice: ColorChoice::CargoAuto,
                tty: atty::is(atty::Stream::Stderr),
            },
            verbosity: Verbosity::Verbose,
        }
    }

    /// Create a shell from a plain writable object, with no color, and max verbosity.
    pub fn from_write(out: Box<Write>) -> Shell {
        Shell {
            err: ShellOut::Write(out),
            verbosity: Verbosity::Verbose,
        }
    }

    /// Print a message, where the status will have `color` color, and can be justified. The
    /// messages follows without color.
    fn print(&mut self,
             status: &fmt::Display,
             message: Option<&fmt::Display>,
             color: Color,
             justified: bool) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => {
                self.err.print(status, message, color, justified)
            }
        }
    }

    /// Returns the width of the terminal in spaces, if any
    pub fn err_width(&self) -> Option<usize> {
        match self.err {
            ShellOut::Stream { tty: true, .. } => imp::stderr_width(),
            _ => None,
        }
    }

    /// Returns whether stderr is a tty
    pub fn is_err_tty(&self) -> bool {
        match self.err {
            ShellOut::Stream { tty, .. } => tty,
            _ => false,
        }
    }

    /// Get a reference to the underlying writer
    pub fn err(&mut self) -> &mut Write {
        self.err.as_write()
    }

    /// Shortcut to right-align and color green a status message.
    pub fn status<T, U>(&mut self, status: T, message: U) -> CargoResult<()>
        where T: fmt::Display, U: fmt::Display
    {
        self.print(&status, Some(&message), Green, true)
    }

    pub fn status_header<T>(&mut self, status: T) -> CargoResult<()>
        where T: fmt::Display,
    {
        self.print(&status, None, Cyan, true)
    }

    /// Shortcut to right-align a status message.
    pub fn status_with_color<T, U>(&mut self,
                                   status: T,
                                   message: U,
                                   color: Color) -> CargoResult<()>
        where T: fmt::Display, U: fmt::Display
    {
        self.print(&status, Some(&message), color, true)
    }

    /// Run the callback only if we are in verbose mode
    pub fn verbose<F>(&mut self, mut callback: F) -> CargoResult<()>
        where F: FnMut(&mut Shell) -> CargoResult<()>
    {
        match self.verbosity {
            Verbosity::Verbose => callback(self),
            _ => Ok(())
        }
    }

    /// Run the callback if we are not in verbose mode.
    pub fn concise<F>(&mut self, mut callback: F) -> CargoResult<()>
        where F: FnMut(&mut Shell) -> CargoResult<()>
    {
        match self.verbosity {
            Verbosity::Verbose => Ok(()),
            _ => callback(self)
        }
    }

    /// Print a red 'error' message
    pub fn error<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        self.print(&"error:", Some(&message), Red, false)
    }

    /// Print an amber 'warning' message
    pub fn warn<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
        match self.verbosity {
            Verbosity::Quiet => Ok(()),
            _ => self.print(&"warning:", Some(&message), Yellow, false),
        }
    }

    /// Update the verbosity of the shell
    pub fn set_verbosity(&mut self, verbosity: Verbosity) {
        self.verbosity = verbosity;
    }

    /// Get the verbosity of the shell
    pub fn verbosity(&self) -> Verbosity {
        self.verbosity
    }

    /// Update the color choice (always, never, or auto) from a string.
    pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
        if let ShellOut::Stream { ref mut stream, ref mut color_choice, .. } =  self.err {
            let cfg = match color {
                Some("always") => ColorChoice::Always,
                Some("never") => ColorChoice::Never,

                Some("auto") |
                None => ColorChoice::CargoAuto,

                Some(arg) => bail!("argument for --color must be auto, always, or \
                                    never, but found `{}`", arg),
            };
            *color_choice = cfg;
            *stream = StandardStream::stderr(cfg.to_termcolor_color_choice());
        }
        Ok(())
    }

    /// Get the current color choice
    ///
    /// If we are not using a color stream, this will always return Never, even if the color choice
    /// has been set to something else.
    pub fn color_choice(&self) -> ColorChoice {
        match self.err {
            ShellOut::Stream { color_choice, .. } => color_choice,
            ShellOut::Write(_) => ColorChoice::Never,
        }
    }
}

impl ShellOut {
    /// Print out a message with a status. The status comes first and is bold + the given color.
    /// The status can be justified, in which case the max width that will right align is 12 chars.
    fn print(&mut self,
             status: &fmt::Display,
             message: Option<&fmt::Display>,
             color: Color,
             justified: bool) -> CargoResult<()> {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => {
                stream.reset()?;
                stream.set_color(ColorSpec::new()
                                    .set_bold(true)
                                    .set_fg(Some(color)))?;
                if justified {
                    write!(stream, "{:>12}", status)?;
                } else {
                    write!(stream, "{}", status)?;
                }
                stream.reset()?;
                match message {
                    Some(message) => write!(stream, " {}\n", message)?,
                    None => write!(stream, " ")?,
                }
            }
            ShellOut::Write(ref mut w) => {
                if justified {
                    write!(w, "{:>12}", status)?;
                } else {
                    write!(w, "{}", status)?;
                }
                match message {
                    Some(message) => write!(w, " {}\n", message)?,
                    None => write!(w, " ")?,
                }
            }
        }
        Ok(())
    }

    /// Get this object as a `io::Write`.
    fn as_write(&mut self) -> &mut Write {
        match *self {
            ShellOut::Stream { ref mut stream, .. } => stream,
            ShellOut::Write(ref mut w) => w,
        }
    }
}

impl ColorChoice {
    /// Convert our color choice to termcolor's version
    fn to_termcolor_color_choice(&self) -> termcolor::ColorChoice {
        match *self {
            ColorChoice::Always => termcolor::ColorChoice::Always,
            ColorChoice::Never => termcolor::ColorChoice::Never,
            ColorChoice::CargoAuto => {
                if atty::is(atty::Stream::Stderr) {
                    termcolor::ColorChoice::Auto
                } else {
                    termcolor::ColorChoice::Never
                }
            }
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
mod imp {
    use std::mem;

    use libc;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let mut winsize: libc::winsize = mem::zeroed();
            if libc::ioctl(libc::STDERR_FILENO, libc::TIOCGWINSZ, &mut winsize) < 0 {
                return None
            }
            if winsize.ws_col > 0 {
                Some(winsize.ws_col as usize)
            } else {
                None
            }
        }
    }
}

#[cfg(all(unix, not(any(target_os = "linux", target_os = "macos"))))]
mod imp {
    pub fn stderr_width() -> Option<usize> {
        None
    }
}

#[cfg(windows)]
mod imp {
    use std::mem;

    extern crate winapi;
    extern crate kernel32;

    pub fn stderr_width() -> Option<usize> {
        unsafe {
            let stdout = kernel32::GetStdHandle(winapi::STD_ERROR_HANDLE);
            let mut csbi: winapi::CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
            if kernel32::GetConsoleScreenBufferInfo(stdout, &mut csbi) == 0 {
                return None
            }
            Some((csbi.srWindow.Right - csbi.srWindow.Left) as usize)
        }
    }
}
<|endoftext|>


<commit_before>use rand::{Rng, SeedableRng, StdRng};
use std::cmp::max;
use std::usize;
use std::collections::{BTreeSet, HashSet};
use petgraph::Graph;
use petgraph::prelude::NodeIndex;
use generators::Gen;
use resources::AstronomicalNamesResource as anr;

/// Basic non deterministic name generator for generating random strings which
/// are similar to the trained data provided.
pub struct NameGen {
    rng: StdRng,
    generated: HashSet<String>,
    graph: Graph<char, f64>,
    start: NodeIndex,
    end: NodeIndex,
    suffixes: Vec<String>
}

impl Gen for NameGen {
    type GenItem = String;
    type TrainData = anr;

    /// Creates a new NameGen with the given seed
    fn new(seed: u32) -> NameGen {

        // Create and initialize random generator using seed
        let new_seed: &[_] = &[seed.clone() as usize];
        let rng: StdRng = SeedableRng::from_seed(new_seed);
        let mut graph = Graph::<char, f64>::new();
        let start = graph.add_node('<');
        let end = graph.add_node('>');
        let generated = HashSet::<String>::new();
        let suffixes = Vec::<String>::new();

        NameGen {
            rng,
            generated,
            graph,
            start,
            end,
            suffixes
        }
    }

    /// Trains the underlying model using the given AstronomicalNamesResource
    fn train(&mut self, data: &anr) {

        let depth = data.names.iter().fold(0, |acc, ref s| max(acc, s.len()));

        // Instansiate layers, number of layers is equal to the longest training
        // string
        let mut layers = Vec::<BTreeSet<NodeIndex>>::new();
        for _ in 0..depth {
            layers.push(BTreeSet::<NodeIndex>::new());
        }

        // Add edges between all characters following each other at every
        // position producing a forward connected graph
        for name in &data.names {
            let chars = name.chars();
            let mut prev = self.start;

            for (index, chr) in chars.enumerate() {
                let node = match layers[index].iter().find(|&&node| {
                    *self.graph.node_weight(node).unwrap() == chr
                }) {
                    Some(&node) => node,
                    _ => self.graph.add_node(chr),
                };
                layers[index].insert(node.clone());

                self.graph.update_edge(prev, node, 0.0);
                prev = node;
            }
            // Add connection to end from last character
            self.graph.update_edge(prev, self.end, 0.0);
        }
        info!(
            "Model has been trained, is using {} layers, {} nodes and {} edges",
            depth,
            self.graph.node_count(),
            self.graph.edge_count()
        );

        // Load suffixes
        self.suffixes.extend_from_slice(&data.greek[..]);
        self.suffixes.extend_from_slice(&data.decorators[..]);
    }

    /// Attempts to generate a new name from the model.
    /// This name is guaranteed to exist in the training set or to have been
    /// previously generated.
    /// Attempts N number of tries, if no unique name could be found it will
    /// return None
    fn generate(&mut self) -> Option<String> {

        // Non deterministicly generate a new string from the model,
        // Note: This may produce an exisiting string in the training set or
        // previously generated set
        fn generate_attempt(
            graph: &Graph<char, f64>,
            start: &NodeIndex,
            end: &NodeIndex,
            rng: &mut StdRng,
        ) -> String {
            let mut final_string = String::new();
            let mut current_node = start.clone();

            // Traverse until we hit end
            while current_node != end.clone() {

                // Step to random neighbor in next layer for which it exists
                // an edge
                let neighbors = graph.neighbors(current_node).collect::<Vec<NodeIndex>>();
                let next_node = rng.choose(neighbors.as_slice()).unwrap();
                final_string.push(*graph.node_weight(current_node).unwrap());
                current_node = *next_node;
            }
            // Remove start node character
            final_string.remove(0);
            final_string
        };

        // Randomly generate a suffix uniformlly from training data, has a high
        // chance of returning None
        // TODO: Load threshold from config
        fn get_suffix(rng: &mut StdRng, suffixes: &Vec<String>) -> Option<String> {
            let suffix_chance = 0.1;
            match rng.next_f64() {
                 x if x < suffix_chance => Some(rng.choose(&suffixes[..]).unwrap().clone()),
                 _ => None
            }
        }

        // Check if a name is valid according to constraints
        // TODO: Extract this to a seperate method, should also probably be
        // based on configuration entries
        let is_valid_name = |name: &String| name.contains(" ") || name.len() < 9;

        // Attempt N number of attempts retuning none if no unique string was
        // generated which fullfils the criteria
        let gen_num_attempts = 27;
        for _ in 0..gen_num_attempts {
            let name = generate_attempt(&self.graph, &self.start, &self.end, &mut self.rng);
            if is_valid_name(&name) && !self.generated.contains(&name) {
                self.generated.insert(name.clone());
                return match get_suffix(&mut self.rng, &self.suffixes) {
                     Some(suffix) => Some(format!("{} {}", name, &suffix)),
                     _ => Some(name)
                }
            }
        }
        info!("Unsuccessful generation used {} tries", gen_num_attempts);
        None

    }
}

#[cfg(test)]
mod names_test {
    use super::*;
    extern crate env_logger;
    use resources::{AstronomicalNamesResource, ResourceHandler};

    #[test]
    // All genrated names must be unique
    fn test_generate_unique() {
        let _ = env_logger::init();

        let mut gen = NameGen::new(0);
        let factory = ResourceHandler::new();
        let res = factory
            .fetch_resource::<AstronomicalNamesResource>()
            .unwrap();
        gen.train(&res);

        let mut names = HashSet::<String>::new();
        for _ in 0..30 {
            names.insert(gen.generate().unwrap());
        }

        assert_eq!(names.len(), 30);
    }
}
<commit_msg>Fix formatting<commit_after>use rand::{Rng, SeedableRng, StdRng};
use std::cmp::max;
use std::usize;
use std::collections::{BTreeSet, HashSet};
use petgraph::Graph;
use petgraph::prelude::NodeIndex;
use generators::Gen;
use resources::AstronomicalNamesResource as anr;

/// Basic non deterministic name generator for generating random strings which
/// are similar to the trained data provided.
pub struct NameGen {
    rng: StdRng,
    generated: HashSet<String>,
    graph: Graph<char, f64>,
    start: NodeIndex,
    end: NodeIndex,
    suffixes: Vec<String>,
}

impl Gen for NameGen {
    type GenItem = String;
    type TrainData = anr;

    /// Creates a new NameGen with the given seed
    fn new(seed: u32) -> NameGen {

        // Create and initialize random generator using seed
        let new_seed: &[_] = &[seed.clone() as usize];
        let rng: StdRng = SeedableRng::from_seed(new_seed);
        let mut graph = Graph::<char, f64>::new();
        let start = graph.add_node('<');
        let end = graph.add_node('>');
        let generated = HashSet::<String>::new();
        let suffixes = Vec::<String>::new();

        NameGen {
            rng,
            generated,
            graph,
            start,
            end,
            suffixes,
        }
    }

    /// Trains the underlying model using the given AstronomicalNamesResource
    fn train(&mut self, data: &anr) {

        let depth = data.names.iter().fold(0, |acc, ref s| max(acc, s.len()));

        // Instansiate layers, number of layers is equal to the longest training
        // string
        let mut layers = Vec::<BTreeSet<NodeIndex>>::new();
        for _ in 0..depth {
            layers.push(BTreeSet::<NodeIndex>::new());
        }

        // Add edges between all characters following each other at every
        // position producing a forward connected graph
        for name in &data.names {
            let chars = name.chars();
            let mut prev = self.start;

            for (index, chr) in chars.enumerate() {
                let node = match layers[index].iter().find(|&&node| {
                    *self.graph.node_weight(node).unwrap() == chr
                }) {
                    Some(&node) => node,
                    _ => self.graph.add_node(chr),
                };
                layers[index].insert(node.clone());

                self.graph.update_edge(prev, node, 0.0);
                prev = node;
            }
            // Add connection to end from last character
            self.graph.update_edge(prev, self.end, 0.0);
        }
        info!(
            "Model has been trained, is using {} layers, {} nodes and {} edges",
            depth,
            self.graph.node_count(),
            self.graph.edge_count()
        );

        // Load suffixes
        self.suffixes.extend_from_slice(&data.greek[..]);
        self.suffixes.extend_from_slice(&data.decorators[..]);
    }

    /// Attempts to generate a new name from the model.
    /// This name is guaranteed to exist in the training set or to have been
    /// previously generated.
    /// Attempts N number of tries, if no unique name could be found it will
    /// return None
    fn generate(&mut self) -> Option<String> {

        // Non deterministicly generate a new string from the model,
        // Note: This may produce an exisiting string in the training set or
        // previously generated set
        fn generate_attempt(
            graph: &Graph<char, f64>,
            start: &NodeIndex,
            end: &NodeIndex,
            rng: &mut StdRng,
        ) -> String {
            let mut final_string = String::new();
            let mut current_node = start.clone();

            // Traverse until we hit end
            while current_node != end.clone() {

                // Step to random neighbor in next layer for which it exists
                // an edge
                let neighbors = graph.neighbors(current_node).collect::<Vec<NodeIndex>>();
                let next_node = rng.choose(neighbors.as_slice()).unwrap();
                final_string.push(*graph.node_weight(current_node).unwrap());
                current_node = *next_node;
            }
            // Remove start node character
            final_string.remove(0);
            final_string
        };

        // Randomly generate a suffix uniformlly from training data, has a high
        // chance of returning None
        // TODO: Load threshold from config
        fn get_suffix(rng: &mut StdRng, suffixes: &Vec<String>) -> Option<String> {
            let suffix_chance = 0.1;
            match rng.next_f64() {
                x if x < suffix_chance => Some(rng.choose(&suffixes[..]).unwrap().clone()),
                _ => None,
            }
        }

        // Check if a name is valid according to constraints
        // TODO: Extract this to a seperate method, should also probably be
        // based on configuration entries
        let is_valid_name = |name: &String| name.contains(" ") || name.len() < 9;

        // Attempt N number of attempts retuning none if no unique string was
        // generated which fullfils the criteria
        let gen_num_attempts = 27;
        for _ in 0..gen_num_attempts {
            let name = generate_attempt(&self.graph, &self.start, &self.end, &mut self.rng);
            if is_valid_name(&name) && !self.generated.contains(&name) {
                self.generated.insert(name.clone());
                return match get_suffix(&mut self.rng, &self.suffixes) {
                    Some(suffix) => Some(format!("{} {}", name, &suffix)),
                    _ => Some(name),
                };
            }
        }
        info!("Unsuccessful generation used {} tries", gen_num_attempts);
        None

    }
}

#[cfg(test)]
mod names_test {
    use super::*;
    extern crate env_logger;
    use resources::{AstronomicalNamesResource, ResourceHandler};

    #[test]
    // All genrated names must be unique
    fn test_generate_unique() {
        let _ = env_logger::init();

        let mut gen = NameGen::new(0);
        let factory = ResourceHandler::new();
        let res = factory
            .fetch_resource::<AstronomicalNamesResource>()
            .unwrap();
        gen.train(&res);

        let mut names = HashSet::<String>::new();
        for _ in 0..30 {
            names.insert(gen.generate().unwrap());
        }

        assert_eq!(names.len(), 30);
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use ast::*;

pub fn factor(rule: Rule) -> Rule {
    match rule {
        Rule { name, ty, expr } => Rule {
            name,
            ty,
            expr: expr.map_top_down(|expr| {
                // TODO: Use box syntax when it gets stabilized.
                match expr {
                    Expr::Choice(lhs, rhs) => match (*lhs, *rhs) {
                        (Expr::Seq(l1, r1), Expr::Seq(l2, r2)) => {
                            if l1 == l2 {
                                Expr::Seq(l1, Box::new(Expr::Choice(r1, r2)))
                            } else {
                                Expr::Choice(
                                    Box::new(Expr::Seq(l1, r1)),
                                    Box::new(Expr::Seq(l2, r2)),
                                )
                            }
                        }
                        // Converts `(l1 ~ l2) | l1` to `l1 ~ l2?`, avoiding trying to match `l1` twice.
                        (Expr::Seq(l1, l2), r) => {
                            if *l1 == r {
                                Expr::Seq(
                                    l1,
                                    Box::new(Expr::Opt(l2))
                                )
                            } else {
                                Expr::Choice(Box::new(Expr::Seq(l1, l2)), Box::new(r))
                            }
                        }
                        // Converts `l | (l ~ r2)` to `l` since `(l ~ r2)` will never match if `l` didn't.
                        (l, Expr::Seq(r1, r2)) => {
                            if l == *r1 {
                                l
                            } else {
                                Expr::Choice(Box::new(l), Box::new(Expr::Seq(r1, r2)))
                            }
                        }
                        (lhs, rhs) => Expr::Choice(Box::new(lhs), Box::new(rhs)),
                    },
                    expr => expr,
                }
            }),
        },
    }
}
<commit_msg>Make the comments rule style consistent with each other<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use ast::*;

pub fn factor(rule: Rule) -> Rule {
    match rule {
        Rule { name, ty, expr } => Rule {
            name,
            ty,
            expr: expr.map_top_down(|expr| {
                // TODO: Use box syntax when it gets stabilized.
                match expr {
                    Expr::Choice(lhs, rhs) => match (*lhs, *rhs) {
                        (Expr::Seq(l1, r1), Expr::Seq(l2, r2)) => {
                            if l1 == l2 {
                                Expr::Seq(l1, Box::new(Expr::Choice(r1, r2)))
                            } else {
                                Expr::Choice(
                                    Box::new(Expr::Seq(l1, r1)),
                                    Box::new(Expr::Seq(l2, r2)),
                                )
                            }
                        }
                        // Converts `(rule ~ rest) | rule` to `rule ~ rest?`, avoiding trying to match `rule` twice.
                        (Expr::Seq(l1, l2), r) => {
                            if *l1 == r {
                                Expr::Seq(
                                    l1,
                                    Box::new(Expr::Opt(l2))
                                )
                            } else {
                                Expr::Choice(Box::new(Expr::Seq(l1, l2)), Box::new(r))
                            }
                        }
                        // Converts `rule | (rule ~ rest)` to `rule` since `(rule ~ rest)`
                        // will never match if `rule` didn't.
                        (l, Expr::Seq(r1, r2)) => {
                            if l == *r1 {
                                l
                            } else {
                                Expr::Choice(Box::new(l), Box::new(Expr::Seq(r1, r2)))
                            }
                        }
                        (lhs, rhs) => Expr::Choice(Box::new(lhs), Box::new(rhs)),
                    },
                    expr => expr,
                }
            }),
        },
    }
}
<|endoftext|>


<commit_before>extern crate native_tls;

use native_tls::{Pkcs12, TlsAcceptor, TlsStream};
use std::fs::File;
use std::io::{Read};
use std::net::{TcpListener, TcpStream};
use std::sync::Arc;
use std::thread;

fn main() {
    let mut file = File::open("identity.pfx").unwrap();
    let mut pkcs12 = vec![];
    file.read_to_end(&mut pkcs12).unwrap();
    let pkcs12 = Pkcs12::from_der(&pkcs12, "hunter2").unwrap();

    let acceptor = TlsAcceptor::builder(pkcs12).unwrap().build().unwrap();
    let acceptor = Arc::new(acceptor);

    let listener = TcpListener::bind("0.0.0.0:8443").unwrap();

    fn handle_client(stream: TlsStream<TcpStream>) {
        // ...
    }

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let acceptor = acceptor.clone();
                thread::spawn(move || {
                    let stream = acceptor.accept(stream).unwrap();
                    handle_client(stream);
                });
            }
            Err(e) => { /* connection failed */ }
        }
    }
}<commit_msg>Fix unused variables<commit_after>extern crate native_tls;

use native_tls::{Pkcs12, TlsAcceptor, TlsStream};
use std::fs::File;
use std::io::{Read};
use std::net::{TcpListener, TcpStream};
use std::sync::Arc;
use std::thread;

fn main() {
    let mut file = File::open("identity.pfx").unwrap();
    let mut pkcs12 = vec![];
    file.read_to_end(&mut pkcs12).unwrap();
    let pkcs12 = Pkcs12::from_der(&pkcs12, "hunter2").unwrap();

    let acceptor = TlsAcceptor::builder(pkcs12).unwrap().build().unwrap();
    let acceptor = Arc::new(acceptor);

    let listener = TcpListener::bind("0.0.0.0:8443").unwrap();

    fn handle_client(_stream: TlsStream<TcpStream>) {
        // ...
    }

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let acceptor = acceptor.clone();
                thread::spawn(move || {
                    let stream = acceptor.accept(stream).unwrap();
                    handle_client(stream);
                });
            }
            Err(_e) => { /* connection failed */ }
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2014-2016 the slack-rs authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// This is a simple example of using slack-rs.
// You can run it with `cargo run --example slack_example -- <api_key>`
//
// NOTE: This will post in the #general channel of the account you connect
// to.
//

use slack;
use slack::{Event, RtmClient};

struct MyHandler;

#[allow(unused_variables)]
impl slack::EventHandler for MyHandler {
    fn on_event(&mut self, cli: &RtmClient, event: Event) {
        println!("on_event(event: {:?})", event);
        if let Event::Hello = event {
            // find the general channel id from the `StartResponse`
            let general_channel_id = cli
                .start_response()
                .channels
                .as_ref()
                .and_then(|channels| {
                    channels.iter().find(|chan| match chan.name {
                        None => false,
                        Some(ref name) => name == "general",
                    })
                })
                .and_then(|chan| chan.id.as_ref())
                .expect("general channel not found");
            let _ = cli
                .sender()
                .send_message(&general_channel_id, "Hello world! (rtm)");
            // Send a message over the real time api websocket
        }
    }

    fn on_close(&mut self, cli: &RtmClient) {
        println!("on_close");
    }

    fn on_connect(&mut self, cli: &RtmClient) {
        println!("on_connect");
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let api_key = match args.len() {
        0 | 1 => {
            panic!("No api-key in args! Usage: cargo run --example slack_example -- <api-key>")
        }
        x => args[x - 1].clone(),
    };
    let mut handler = MyHandler;
    let r = RtmClient::login_and_run(&api_key, &mut handler);
    match r {
        Ok(_) => {}
        Err(err) => panic!("Error: {}", err),
    }
}
<commit_msg>add note in example about class apps<commit_after>//
// Copyright 2014-2016 the slack-rs authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// This is a simple example of using slack-rs.
// You can run it with `cargo run --example slack_example -- <api_key>`
//
// NOTE: Only classic app bots can connect to rtm https://api.slack.com/rtm#classic
//
// NOTE: This will post in the #general channel of the account you connect
// to.
//

use slack;
use slack::{Event, RtmClient};

struct MyHandler;

#[allow(unused_variables)]
impl slack::EventHandler for MyHandler {
    fn on_event(&mut self, cli: &RtmClient, event: Event) {
        println!("on_event(event: {:?})", event);
        if let Event::Hello = event {
            // find the general channel id from the `StartResponse`
            let general_channel_id = cli
                .start_response()
                .channels
                .as_ref()
                .and_then(|channels| {
                    channels.iter().find(|chan| match chan.name {
                        None => false,
                        Some(ref name) => name == "general",
                    })
                })
                .and_then(|chan| chan.id.as_ref())
                .expect("general channel not found");
            let _ = cli
                .sender()
                .send_message(&general_channel_id, "Hello world! (rtm)");
            // Send a message over the real time api websocket
        }
    }

    fn on_close(&mut self, cli: &RtmClient) {
        println!("on_close");
    }

    fn on_connect(&mut self, cli: &RtmClient) {
        println!("on_connect");
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let api_key = match args.len() {
        0 | 1 => {
            panic!("No api-key in args! Usage: cargo run --example slack_example -- <api-key>")
        }
        x => args[x - 1].clone(),
    };
    let mut handler = MyHandler;
    let r = RtmClient::login_and_run(&api_key, &mut handler);
    match r {
        Ok(_) => {}
        Err(err) => panic!("Error: {}", err),
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;
use std::io::{ Read, Write };
use std::path::Path;

use reqwest;
use reqwest::header::{ ContentLength, Header, HeaderFormat};

#[macro_use]
use macros;

pub fn download_file_while<F>(url: &str, output: &Path, and: F) -> Result<u64, String>
    where F: Fn(u64, &u64) {
    let response = get!(reqwest::get(url), "Error occured while making a GET request. Reason:\n");
    let mut target = get!(File::create(output), "Error occured while creating file. Reason:\n");

    let length = match response.headers().get::<ContentLength>() {
        Some(x) => **x,
        None => 0u64
    };

    let mut bytes_completed = 0u64;
    for byte in response.bytes() {
        target.write(&[byte.unwrap()]).unwrap();
        bytes_completed += 1;
        and(length, &bytes_completed)
    }

    Ok(length)
}

pub fn download_file_and<F>(url: &str, output: &Path, and: F) -> Result<u64, String>
    where F: Fn(u64) {
    let length = try!(download_file_while(url, output, |_, _| { }));
    and(length);
    Ok(length)
}

pub fn download_file(url: &str, output: &Path) -> Result<u64, String> {
    download_file_and(url, output, |_| { }) // Do nothing for and.
}
<commit_msg>Switch to use BufWriter instead of typical Write<commit_after>use std::error::Error;
use std::fs::File;
use std::io::{ BufWriter, Read, Write };
use std::path::{ Path, PathBuf };

use reqwest;
use reqwest::header::{ ContentLength, Header, HeaderFormat};

#[macro_use]
use macros;

pub fn download_file_while<F>(url: &str, output: &Path, and: F) -> Result<u64, String>
    where F: Fn(u64, &u64) {

    // Abandoning this code, as the filename is going to be unpredictable in this case.
    /*let mut output_to = PathBuf::new();
            output_to.push(output);
            output_to.push(url.split('/').last().unwrap_or("_error_"));*/

    let response = get!(reqwest::get(url), "Error occured while making a GET request. Reason:\n");
    let target = get!(File::create(output), "Error occured while creating file. Reason:\n");
    let mut target = BufWriter::new(target);

    let length = match response.headers().get::<ContentLength>() {
        Some(x) => **x,
        None => 0u64
    };

    let mut bytes_completed = 0u64;
    for byte in response.bytes() {
        target.write(&[byte.unwrap()]).unwrap();
        bytes_completed += 1;
        and(length, &bytes_completed)
    }

    Ok(length)
}

pub fn download_file_and<F>(url: &str, output: &Path, and: F) -> Result<u64, String>
    where F: Fn(u64) {
    let length = try!(download_file_while(url, output, |_, _| { }));
    and(length);
    Ok(length)
}

pub fn download_file(url: &str, output: &Path) -> Result<u64, String> {
    download_file_and(url, output, |_| { }) // Do nothing for and.
}
<|endoftext|>


<commit_before>use neb::ram::cell::Cell;
use neb::ram::types::{TypeId, Id, key_hash, Map, Value};
use neb::client::transaction::{Transaction, TxnError};
use graph::fields::*;
use graph::id_list::{IdList, IdListError};
use graph::edge;
use server::schema::SchemaContainer;

use std::sync::Arc;
use super::EdgeDirection;

pub struct Vertex {
    pub cell: Cell
}

pub enum RemoveError {
    NotFound,
    FormatError,
    IdListError(IdListError),
    EdgeError(edge::EdgeError)
}

pub fn cell_to_vertex(cell: Cell) -> Vertex {
    Vertex {
        cell: cell
    }
}

pub fn vertex_to_cell(vertex: Vertex) -> Cell {
    vertex.cell
}

impl Vertex {
    pub fn new(schema: u32, data: Map) -> Vertex {
        Vertex {
            cell: Cell::new_with_id(schema, &Id::unit_id(), Value::Map(data))
        }
    }
    pub fn schema(&self) -> u32 {
        self.cell.header.schema
    }
}

pub fn txn_remove(txn: &mut Transaction, schemas: &Arc<SchemaContainer>, id: &Id) -> Result<Result<(), RemoveError>, TxnError> {
    match txn.read(id)? {
        Some(cell) => {
            let remove_field_lists = |id: &Id, txn: &mut Transaction, field_id: u64|
                -> Result<Result<(), RemoveError>, TxnError> {
                let (type_list_id, schemas_ids) = match IdList::cell_types(txn, id, field_id)? {
                    Some(t) => t, None => return Ok(Err(RemoveError::FormatError))
                };
                for schema_id in schemas_ids {
                    let mut id_list = IdList::from_txn_and_container(txn, id, field_id, schema_id);
                    {                          // remove edge cells
                        let mut iter = match id_list.iter()? {
                            Ok(iter) => iter, Err(e) => return Ok(Err(RemoveError::IdListError(e)))
                        };
                        while let Some(edge_id) = iter.next() {
                            let edge = match edge::from_id(
                                id, field_id, schema_id, schemas,
                                iter.segments.id_iter.txn, &edge_id
                            )? {
                                Ok(edge) => edge, Err(e) => return Ok(Err(RemoveError::EdgeError(e)))
                            };
                            match edge.remove(iter.segments.id_iter.txn)? {
                                Ok(()) => {}, Err(e) => return Ok(Err(RemoveError::EdgeError(e)))
                            }
                        }
                    }
                    match id_list.clear_segments()? { // remove segment cells
                        Ok(()) => {}, Err(e) => return Ok(Err(RemoveError::IdListError(e)))
                    }
                }
                txn.remove(&type_list_id)?; // remove field schema list cell
                Ok(Ok(()))
            };
            remove_field_lists(id, txn, EdgeDirection::Undirected.as_field());
            remove_field_lists(id, txn, EdgeDirection::Outbound.as_field());
            remove_field_lists(id, txn, EdgeDirection::Inbound.as_field());
            txn.remove(id).map(|_| Ok(())) // remove vertex cell
        },
        None => Ok(Err(RemoveError::NotFound))
    }
}

pub fn txn_update<U>(txn: &mut Transaction, id: &Id, update: &U) -> Result<(), TxnError>
    where U: Fn(Vertex) -> Option<Vertex> {
    let update_cell = |cell: Cell| {
        match update(cell_to_vertex(cell)) {
            Some(vertex) => Some(vertex_to_cell(vertex)),
            None => None
        }
    };
    let cell = txn.read(id)?;
    match cell {
        Some(cell) => {
            match update_cell(cell) {
                Some(cell) => txn.update(&cell),
                None => txn.abort()
            }
        },
        None => txn.abort()
    }
}<commit_msg>cope with errors<commit_after>use neb::ram::cell::Cell;
use neb::ram::types::{TypeId, Id, key_hash, Map, Value};
use neb::client::transaction::{Transaction, TxnError};
use graph::fields::*;
use graph::id_list::{IdList, IdListError};
use graph::edge;
use server::schema::SchemaContainer;

use std::sync::Arc;
use super::EdgeDirection;

pub struct Vertex {
    pub cell: Cell
}

pub enum RemoveError {
    NotFound,
    FormatError,
    IdListError(IdListError),
    EdgeError(edge::EdgeError)
}

pub fn cell_to_vertex(cell: Cell) -> Vertex {
    Vertex {
        cell: cell
    }
}

pub fn vertex_to_cell(vertex: Vertex) -> Cell {
    vertex.cell
}

impl Vertex {
    pub fn new(schema: u32, data: Map) -> Vertex {
        Vertex {
            cell: Cell::new_with_id(schema, &Id::unit_id(), Value::Map(data))
        }
    }
    pub fn schema(&self) -> u32 {
        self.cell.header.schema
    }
}

pub fn txn_remove(txn: &mut Transaction, schemas: &Arc<SchemaContainer>, id: &Id) -> Result<Result<(), RemoveError>, TxnError> {
    match txn.read(id)? {
        Some(cell) => {
            let remove_field_lists = |id: &Id, txn: &mut Transaction, field_id: u64|
                -> Result<Result<(), RemoveError>, TxnError> {
                let (type_list_id, schemas_ids) = match IdList::cell_types(txn, id, field_id)? {
                    Some(t) => t, None => return Ok(Err(RemoveError::FormatError))
                };
                for schema_id in schemas_ids {
                    let mut id_list = IdList::from_txn_and_container(txn, id, field_id, schema_id);
                    {                          // remove edge cells
                        let mut iter = match id_list.iter()? {
                            Ok(iter) => iter, Err(e) => return Ok(Err(RemoveError::IdListError(e)))
                        };
                        while let Some(edge_id) = iter.next() {
                            let edge = match edge::from_id(
                                id, field_id, schema_id, schemas,
                                iter.segments.id_iter.txn, &edge_id
                            )? {
                                Ok(edge) => edge, Err(e) => return Ok(Err(RemoveError::EdgeError(e)))
                            };
                            match edge.remove(iter.segments.id_iter.txn)? {
                                Ok(()) => {}, Err(e) => return Ok(Err(RemoveError::EdgeError(e)))
                            }
                        }
                    }
                    match id_list.clear_segments()? { // remove segment cells
                        Ok(()) => {}, Err(e) => return Ok(Err(RemoveError::IdListError(e)))
                    }
                }
                txn.remove(&type_list_id)?; // remove field schema list cell
                Ok(Ok(()))
            };
            match remove_field_lists(id, txn, EdgeDirection::Undirected.as_field())? {
                Ok(()) => {}, Err(e) => return Ok(Err(e))
            }
            match remove_field_lists(id, txn, EdgeDirection::Inbound.as_field())? {
                Ok(()) => {}, Err(e) => return Ok(Err(e))
            }
            match remove_field_lists(id, txn, EdgeDirection::Outbound.as_field())? {
                Ok(()) => {}, Err(e) => return Ok(Err(e))
            }
            txn.remove(id).map(|_| Ok(())) // remove vertex cell
        },
        None => Ok(Err(RemoveError::NotFound))
    }
}

pub fn txn_update<U>(txn: &mut Transaction, id: &Id, update: &U) -> Result<(), TxnError>
    where U: Fn(Vertex) -> Option<Vertex> {
    let update_cell = |cell: Cell| {
        match update(cell_to_vertex(cell)) {
            Some(vertex) => Some(vertex_to_cell(vertex)),
            None => None
        }
    };
    let cell = txn.read(id)?;
    match cell {
        Some(cell) => {
            match update_cell(cell) {
                Some(cell) => txn.update(&cell),
                None => txn.abort()
            }
        },
        None => txn.abort()
    }
}<|endoftext|>


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

use library;
use analysis;
use analysis::bounds::Bounds;
use analysis::functions::Visibility;
use analysis::namespaces;
use chunk::{ffi_function_todo, Chunk};
use env::Env;
use super::function_body_chunk;
use super::general::{
    cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition,
};
use super::parameter::ToParameter;
use super::return_value::{out_parameters_as_return, ToReturnValue};
use writer::primitives::tabs;
use writer::ToCode;

use std::result::Result as StdResult;
use std::fmt;

pub fn generate(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::functions::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    if analysis.is_async_finish(env) {
        return Ok(());
    }

    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };

    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => if in_trait {
            warn!(
                "Generating trait method for private function {}",
                analysis.glib_name
            );
        } else {
            pub_prefix = "";
        },
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    try!(writeln!(w));
    if !in_trait || only_declaration {
        try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent));
    }
    try!(cfg_condition(w, &analysis.cfg_condition, commented, indent));
    try!(version_condition(
        w,
        env,
        analysis.version,
        commented,
        indent,
    ));
    try!(not_version_condition(
        w,
        analysis.not_version,
        commented,
        indent,
    ));
    try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent));
    try!(writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix
    ));

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            try!(writeln!(w, "{}{}", tabs(indent), s));
        }
    }

    if analysis.async_future.is_some() {
        let declaration = declaration_futures(env, analysis);
        let suffix = if only_declaration { ";" } else { " {" };

        try!(writeln!(w));
        if !in_trait || only_declaration {
            try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent));
        }

        try!(writeln!(w, "{}{}#[cfg(feature = \"futures\")]", tabs(indent), comment_prefix));
        try!(cfg_condition(w, &analysis.cfg_condition, commented, indent));
        try!(version_condition(
            w,
            env,
            analysis.version,
            commented,
            indent,
        ));
        try!(not_version_condition(
            w,
            analysis.not_version,
            commented,
            indent,
        ));
        try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent));
        try!(writeln!(
            w,
            "{}{}{}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            declaration,
            suffix
        ));

        if !only_declaration {
            let body = body_chunk_futures(env, analysis).unwrap();
            for s in body.lines() {
                if !s.is_empty() {
                    try!(writeln!(w, "{}{}{}", tabs(indent+1), comment_prefix, s));
                } else {
                    try!(writeln!(w));
                }
            }
            try!(writeln!(w, "{}{}}}", tabs(indent), comment_prefix));
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else if analysis.ret.bool_return_is_error.is_some() {
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            " -> Result<(), error::BoolError>".into()
        } else {
            " -> Result<(), glib::error::BoolError>".into()
        }
    } else {
        analysis.ret.to_return_value(env)
    };
    let mut param_str = String::with_capacity(100);

    let bounds = bounds(&analysis.bounds, &[], false);

    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        if pos > 0 {
            param_str.push_str(", ")
        }
        let c_par = &analysis.parameters.c_parameters[par.ind_c];
        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    format!(
        "fn {}{}({}){}",
        analysis.name,
        bounds,
        param_str,
        return_str
    )
}

pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String {
    let async_future = analysis.async_future.as_ref().unwrap();

    let return_str = if async_future.is_method {
        format!(" -> Box_<futures_core::Future<Item = (Self, {}), Error = (Self, {})>>", async_future.success_parameters, async_future.error_parameters)
    } else {
        format!(" -> Box_<futures_core::Future<Item = {}, Error = {}>>", async_future.success_parameters, async_future.error_parameters)
    };

    let mut param_str = String::with_capacity(100);

    let mut skipped = 0;
    let mut skipped_bounds = vec![];
    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        if c_par.name == "callback" || c_par.name == "cancellable" {
            skipped += 1;
            if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) {
                skipped_bounds.push(t);
            }
            continue;
        }

        if pos - skipped > 0 {
            param_str.push_str(", ")
        }

        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    let bounds = bounds(&analysis.bounds, skipped_bounds.as_ref(), true);

    format!(
        "fn {}{}({}){}",
        async_future.name,
        bounds,
        param_str,
        return_str
    )
}

pub fn bounds(bounds: &Bounds, skip: &[char], async: bool) -> String {
    use analysis::bounds::BoundType::*;
    if bounds.is_empty() {
        return String::new();
    }

    let skip_lifetimes = bounds.iter()
        .filter(|bound| skip.contains(&bound.alias))
        .filter_map(|bound| match bound.bound_type {
            IsA(Some(lifetime)) |
            AsRef(Some(lifetime)) |
            Into(Some(lifetime), _) => Some(lifetime),
            _ => None,
        })
        .collect::<Vec<_>>();

    let strs: Vec<String> = bounds
        .iter_lifetimes()
        .filter(|s| !skip_lifetimes.contains(s))
        .map(|s| format!("'{}", s))
        .chain(bounds.iter().filter(|bound| !skip.contains(&bound.alias)).map(|bound| match bound.bound_type {
            NoWrapper => {
                format!("{}: {}", bound.alias, bound.type_str)
            }
            IsA(Some(lifetime)) => {
                format!("{}: IsA<{}> + {}", bound.alias, bound.type_str, if async { "Clone + 'static".into() } else { format!("'{}", lifetime) })
            }
            IsA(None) => format!("{}: IsA<{}>{}", bound.alias, bound.type_str, if async { " + Clone + 'static" } else { "" }),
            // This case should normally never happened
            AsRef(Some(lifetime)) => {
                format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime)
            }
            AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str),
            Into(Some(l), _) => {
                format!("{}: Into<Option<&'{} {}>>", bound.alias, l, bound.type_str)
            }
            Into(None, _) => format!("{}: Into<Option<{}>>", bound.alias, bound.type_str),
        }))
        .collect();

    if strs.is_empty() {
        String::new()
    } else {
        format!("<{}>", strs.join(", "))
    }
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(&analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();

    let mut builder = function_body_chunk::Builder::new();
    builder
        .glib_name(&analysis.glib_name)
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .transformations(&analysis.parameters.transformations)
        .outs_mode(analysis.outs.mode);

    if analysis.async {
        if let Some(ref trampoline) = analysis.trampoline {
            builder.async_trampoline(trampoline);
        } else {
            warn!("Async function {} has no associated _finish function", analysis.name);
        }
    }

    for par in &analysis.parameters.c_parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) {
            builder.out_parameter(env, par);
        } else {
            builder.parameter();
        }
    }

    builder.generate(env)
}

pub fn body_chunk_futures(env: &Env, analysis: &analysis::functions::Info) -> StdResult<String, fmt::Error> {
    use std::fmt::Write;
    use analysis::bounds::BoundType;
    use analysis::ref_mode::RefMode;

    let async_future = analysis.async_future.as_ref().unwrap();

    let mut body = String::new();

    if env.config.library_name != "Gio" {
        try!(writeln!(body, "use gio::GioFuture;"));
    } else {
        try!(writeln!(body, "use GioFuture;"));
    }
    try!(writeln!(body, "use send_cell::SendCell;"));
    try!(writeln!(body));

    let skip = if async_future.is_method { 1 } else { 0 };

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" || par.name == "callback" {
            continue;
        }

        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        let bounds = analysis.bounds.get_parameter_alias_info(&par.name);
        let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false };

        let type_ = env.type_(par.typ);
        let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ { true } else { false };

        if is_into {
            try!(writeln!(body, "let {} = {}.into();", par.name, par.name));
            if is_str {
                try!(writeln!(body, "let {} = {}.map(String::from);", par.name, par.name));
            } else if c_par.nullable.0 {
                try!(writeln!(body, "let {} = {}.cloned();", par.name, par.name));
            }
        } else if is_str {
            try!(writeln!(body, "let {} = String::from({});", par.name, par.name));
        } else if c_par.ref_mode != RefMode::None {
            try!(writeln!(body, "let {} = {}.clone();", par.name, par.name));
        }
    }

    if async_future.is_method {
        try!(writeln!(body, "GioFuture::new(self, move |obj, send| {{"));
    } else {
        try!(writeln!(body, "GioFuture::new(&(), move |_obj, send| {{"));
    }

    if env.config.library_name != "Gio" {
        try!(writeln!(body, "    let cancellable = gio::Cancellable::new();"));
    } else {
        try!(writeln!(body, "    let cancellable = Cancellable::new();"));
    }
    try!(writeln!(body, "    let send = SendCell::new(send);"));

    if async_future.is_method {
        try!(writeln!(body, "    let obj_clone = SendCell::new(obj.clone());"));
        try!(writeln!(body, "    obj.{}(", analysis.name));
    } else if analysis.type_name.is_ok() {
        try!(writeln!(body, "    Self::{}(", analysis.name));
    } else {
        try!(writeln!(body, "    {}(", analysis.name));
    }

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" {
            try!(writeln!(body, "         Some(&cancellable),"));
        } else if par.name == "callback" {
            continue;
        } else {
            let c_par = &analysis.parameters.c_parameters[par.ind_c];

            let bounds = analysis.bounds.get_parameter_alias_info(&par.name);
            let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false };

            let type_ = env.type_(par.typ);
            let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ { true } else { false };

            if is_into && is_str {
                try!(writeln!(body, "         {}.as_ref().map(|s| s.as_str()),", par.name));
            } else if is_into && c_par.nullable.0 {
                try!(writeln!(body, "         {}.as_ref(),", par.name));
            } else if c_par.ref_mode != RefMode::None {
                try!(writeln!(body, "         &{},", par.name));
            } else {
                try!(writeln!(body, "         {},", par.name));
            }
        }
    }

    try!(writeln!(body, "         move |res| {{"));
    if async_future.is_method {
        try!(writeln!(body, "             let obj = obj_clone.into_inner();"));
        try!(writeln!(body, "             let res = res.map(|v| (obj.clone(), v)).map_err(|v| (obj.clone(), v));"));
    }
    try!(writeln!(body, "             let _ = send.into_inner().send(res);"));
    try!(writeln!(body, "         }},"));
    try!(writeln!(body, "    );"));
    try!(writeln!(body));
    try!(writeln!(body, "    cancellable"));
    try!(writeln!(body, "}})"));

    Ok(body)
}
<commit_msg>Use ToOwned and Borrow traits when generating futures.<commit_after>use std::io::{Result, Write};

use library;
use analysis;
use analysis::bounds::Bounds;
use analysis::functions::Visibility;
use analysis::namespaces;
use chunk::{ffi_function_todo, Chunk};
use env::Env;
use super::function_body_chunk;
use super::general::{
    cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition,
};
use super::parameter::ToParameter;
use super::return_value::{out_parameters_as_return, ToReturnValue};
use writer::primitives::tabs;
use writer::ToCode;

use std::result::Result as StdResult;
use std::fmt;

pub fn generate(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::functions::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    if analysis.is_async_finish(env) {
        return Ok(());
    }

    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };

    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => if in_trait {
            warn!(
                "Generating trait method for private function {}",
                analysis.glib_name
            );
        } else {
            pub_prefix = "";
        },
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    try!(writeln!(w));
    if !in_trait || only_declaration {
        try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent));
    }
    try!(cfg_condition(w, &analysis.cfg_condition, commented, indent));
    try!(version_condition(
        w,
        env,
        analysis.version,
        commented,
        indent,
    ));
    try!(not_version_condition(
        w,
        analysis.not_version,
        commented,
        indent,
    ));
    try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent));
    try!(writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix
    ));

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            try!(writeln!(w, "{}{}", tabs(indent), s));
        }
    }

    if analysis.async_future.is_some() {
        let declaration = declaration_futures(env, analysis);
        let suffix = if only_declaration { ";" } else { " {" };

        try!(writeln!(w));
        if !in_trait || only_declaration {
            try!(cfg_deprecated(w, env, analysis.deprecated_version, commented, indent));
        }

        try!(writeln!(w, "{}{}#[cfg(feature = \"futures\")]", tabs(indent), comment_prefix));
        try!(cfg_condition(w, &analysis.cfg_condition, commented, indent));
        try!(version_condition(
            w,
            env,
            analysis.version,
            commented,
            indent,
        ));
        try!(not_version_condition(
            w,
            analysis.not_version,
            commented,
            indent,
        ));
        try!(doc_hidden(w, analysis.doc_hidden, comment_prefix, indent));
        try!(writeln!(
            w,
            "{}{}{}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            declaration,
            suffix
        ));

        if !only_declaration {
            let body = body_chunk_futures(env, analysis).unwrap();
            for s in body.lines() {
                if !s.is_empty() {
                    try!(writeln!(w, "{}{}{}", tabs(indent+1), comment_prefix, s));
                } else {
                    try!(writeln!(w));
                }
            }
            try!(writeln!(w, "{}{}}}", tabs(indent), comment_prefix));
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else if analysis.ret.bool_return_is_error.is_some() {
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            " -> Result<(), error::BoolError>".into()
        } else {
            " -> Result<(), glib::error::BoolError>".into()
        }
    } else {
        analysis.ret.to_return_value(env)
    };
    let mut param_str = String::with_capacity(100);

    let bounds = bounds(&analysis.bounds, &[], false);

    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        if pos > 0 {
            param_str.push_str(", ")
        }
        let c_par = &analysis.parameters.c_parameters[par.ind_c];
        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    format!(
        "fn {}{}({}){}",
        analysis.name,
        bounds,
        param_str,
        return_str
    )
}

pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String {
    let async_future = analysis.async_future.as_ref().unwrap();

    let return_str = if async_future.is_method {
        format!(" -> Box_<futures_core::Future<Item = (Self, {}), Error = (Self, {})>>", async_future.success_parameters, async_future.error_parameters)
    } else {
        format!(" -> Box_<futures_core::Future<Item = {}, Error = {}>>", async_future.success_parameters, async_future.error_parameters)
    };

    let mut param_str = String::with_capacity(100);

    let mut skipped = 0;
    let mut skipped_bounds = vec![];
    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        if c_par.name == "callback" || c_par.name == "cancellable" {
            skipped += 1;
            if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) {
                skipped_bounds.push(t);
            }
            continue;
        }

        if pos - skipped > 0 {
            param_str.push_str(", ")
        }

        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    let bounds = bounds(&analysis.bounds, skipped_bounds.as_ref(), true);

    format!(
        "fn {}{}({}){}",
        async_future.name,
        bounds,
        param_str,
        return_str
    )
}

pub fn bounds(bounds: &Bounds, skip: &[char], async: bool) -> String {
    use analysis::bounds::BoundType::*;
    if bounds.is_empty() {
        return String::new();
    }

    let skip_lifetimes = bounds.iter()
        .filter(|bound| skip.contains(&bound.alias))
        .filter_map(|bound| match bound.bound_type {
            IsA(Some(lifetime)) |
            AsRef(Some(lifetime)) |
            Into(Some(lifetime), _) => Some(lifetime),
            _ => None,
        })
        .collect::<Vec<_>>();

    let strs: Vec<String> = bounds
        .iter_lifetimes()
        .filter(|s| !skip_lifetimes.contains(s))
        .map(|s| format!("'{}", s))
        .chain(bounds.iter().filter(|bound| !skip.contains(&bound.alias)).map(|bound| match bound.bound_type {
            NoWrapper => {
                format!("{}: {}", bound.alias, bound.type_str)
            }
            IsA(Some(lifetime)) => {
                format!("{}: IsA<{}> + {}", bound.alias, bound.type_str, if async { "Clone + 'static".into() } else { format!("'{}", lifetime) })
            }
            IsA(None) => format!("{}: IsA<{}>{}", bound.alias, bound.type_str, if async { " + Clone + 'static" } else { "" }),
            // This case should normally never happened
            AsRef(Some(lifetime)) => {
                format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime)
            }
            AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str),
            Into(Some(l), _) => {
                format!("{}: Into<Option<&'{} {}>>", bound.alias, l, bound.type_str)
            }
            Into(None, _) => format!("{}: Into<Option<{}>>", bound.alias, bound.type_str),
        }))
        .collect();

    if strs.is_empty() {
        String::new()
    } else {
        format!("<{}>", strs.join(", "))
    }
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(&analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();

    let mut builder = function_body_chunk::Builder::new();
    builder
        .glib_name(&analysis.glib_name)
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .transformations(&analysis.parameters.transformations)
        .outs_mode(analysis.outs.mode);

    if analysis.async {
        if let Some(ref trampoline) = analysis.trampoline {
            builder.async_trampoline(trampoline);
        } else {
            warn!("Async function {} has no associated _finish function", analysis.name);
        }
    }

    for par in &analysis.parameters.c_parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) {
            builder.out_parameter(env, par);
        } else {
            builder.parameter();
        }
    }

    builder.generate(env)
}

pub fn body_chunk_futures(env: &Env, analysis: &analysis::functions::Info) -> StdResult<String, fmt::Error> {
    use std::fmt::Write;
    use analysis::bounds::BoundType;
    use analysis::ref_mode::RefMode;

    let async_future = analysis.async_future.as_ref().unwrap();

    let mut body = String::new();

    if env.config.library_name != "Gio" {
        try!(writeln!(body, "use gio::GioFuture;"));
    } else {
        try!(writeln!(body, "use GioFuture;"));
    }
    try!(writeln!(body, "use send_cell::SendCell;"));
    try!(writeln!(body));

    let skip = if async_future.is_method { 1 } else { 0 };

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" || par.name == "callback" {
            continue;
        }

        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        let bounds = analysis.bounds.get_parameter_alias_info(&par.name);
        let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false };

        let type_ = env.type_(par.typ);
        let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ { true } else { false };

        if is_into {
            try!(writeln!(body, "let {} = {}.into();", par.name, par.name));
            if is_str || c_par.nullable.0 {
                try!(writeln!(body, "let {} = {}.map(ToOwned::to_owned);", par.name, par.name));
            }
        } else if is_str {
            try!(writeln!(body, "let {} = String::from({});", par.name, par.name));
        } else if c_par.ref_mode != RefMode::None {
            try!(writeln!(body, "let {} = {}.clone();", par.name, par.name));
        }
    }

    if async_future.is_method {
        try!(writeln!(body, "GioFuture::new(self, move |obj, send| {{"));
    } else {
        try!(writeln!(body, "GioFuture::new(&(), move |_obj, send| {{"));
    }

    if env.config.library_name != "Gio" {
        try!(writeln!(body, "    let cancellable = gio::Cancellable::new();"));
    } else {
        try!(writeln!(body, "    let cancellable = Cancellable::new();"));
    }
    try!(writeln!(body, "    let send = SendCell::new(send);"));

    if async_future.is_method {
        try!(writeln!(body, "    let obj_clone = SendCell::new(obj.clone());"));
        try!(writeln!(body, "    obj.{}(", analysis.name));
    } else if analysis.type_name.is_ok() {
        try!(writeln!(body, "    Self::{}(", analysis.name));
    } else {
        try!(writeln!(body, "    {}(", analysis.name));
    }

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" {
            try!(writeln!(body, "         Some(&cancellable),"));
        } else if par.name == "callback" {
            continue;
        } else {
            let c_par = &analysis.parameters.c_parameters[par.ind_c];

            let bounds = analysis.bounds.get_parameter_alias_info(&par.name);
            let is_into = if let Some((_, BoundType::Into(..))) = bounds { true } else { false };

            if is_into {
                try!(writeln!(body, "         {}.as_ref().map(::std::borrow::Borrow::borrow),", par.name));
            } else if c_par.ref_mode != RefMode::None {
                try!(writeln!(body, "         &{},", par.name));
            } else {
                try!(writeln!(body, "         {},", par.name));
            }
        }
    }

    try!(writeln!(body, "         move |res| {{"));
    if async_future.is_method {
        try!(writeln!(body, "             let obj = obj_clone.into_inner();"));
        try!(writeln!(body, "             let res = res.map(|v| (obj.clone(), v)).map_err(|v| (obj.clone(), v));"));
    }
    try!(writeln!(body, "             let _ = send.into_inner().send(res);"));
    try!(writeln!(body, "         }},"));
    try!(writeln!(body, "    );"));
    try!(writeln!(body));
    try!(writeln!(body, "    cancellable"));
    try!(writeln!(body, "}})"));

    Ok(body)
}
<|endoftext|>