<commit_before>use messages::outgoing;
use mio;
use node::Node;
use node;
use routing_table::{InsertOutcome, RoutingTable};
use routing_table;
use std::collections::HashMap;
use std::io::Cursor;
use std::thread;
use transaction::{TransactionId, TransactionIdGenerator};

pub enum ScheduledTask {
    ContinueBootstrap
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap
}

enum TableAction {
    Bootstrap(mio::Timeout)
}

enum Status {
    Bootstrapped,
    Bootstrapping,
    Idle
}

pub struct Handler {
    port: u16,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>
}

impl Handler {
    pub fn new<N: node::Node + 'static>(self_node: N, port: u16, routers: Vec<Box<Node>>) -> Handler {
        let self_address = self_node.get_address();
        let routing_table = routing_table::RoutingTable::new(8, self_address, routers);

        Handler {
            port: port,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new()
        }
    }

    pub fn run(mut self) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let loop_channel = event_loop.channel();

        create_incoming_udp_channel(self.port, loop_channel.clone());
        loop_channel.send(OneshotTask::StartBootstrap).unwrap();
        event_loop.run(&mut self).unwrap();
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming;
        use messages::incoming::*;
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();
        println!("Routing table: {:?}", self.routing_table);

        match message {
            Message::Query(transaction_id, query) => {
                match query {
                    Query::FindNode(origin, target) => {
                        {
                            let nodes: Vec<&Box<node::Node>> = self.routing_table.nearest_to(&target);
                            let response = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                nodes);
                            origin.send(response);
                        }

                        self.routing_table.insert(origin).unwrap();
                    }
                }
            }
            Message::Response(transaction_id, response) => {
                match response {
                    Response::FindNode(origin, mut nodes) => {
                        let mut encounted_new_node = false;
                        let mut tail = vec![origin];
                        for node in nodes.drain(..).chain(tail.drain(..)) {
                            match self.routing_table.insert(node) {
                                Ok(InsertOutcome::Inserted) => { encounted_new_node = true; }
                                _ => { }
                            }
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                if encounted_new_node {
                                    // Continue botstrapping
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.status = Status::Bootstrapped;
                                }
                            }
                            _ => { }
                        }
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        let transaction_id = self.find_self();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn find_self(&mut self) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            self.self_node.get_address());
        if let Some(node) = self.routing_table.nearest().get(0) {
            node.send(query);
        }
        transaction_id
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.start_bootstrap(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.continue_bootstrap(event_loop)
        }
    }
}

fn create_incoming_udp_channel(port: u16, sender: mio::Sender<OneshotTask>) {
    use std::net::UdpSocket;
    thread::spawn(move || {
        let address = ("0.0.0.0", port);
        let socket = UdpSocket::bind(address).unwrap();
        loop {
            let mut buf = [0; 4096];
            match socket.recv_from(&mut buf) {
                Ok((size, _src)) => {
                    sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect())).unwrap();
                }
                Err(e) => panic!("Error receiving from server: {}", e)
            }
        }
    });
}
<commit_msg>Remove unnecessary enum Bootstrapped<commit_after>use messages::outgoing;
use mio;
use node::Node;
use node;
use routing_table::{InsertOutcome, RoutingTable};
use routing_table;
use std::collections::HashMap;
use std::io::Cursor;
use std::thread;
use transaction::{TransactionId, TransactionIdGenerator};

pub enum ScheduledTask {
    ContinueBootstrap
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap
}

enum TableAction {
    Bootstrap(mio::Timeout)
}

enum Status {
    Bootstrapping,
    Idle
}

pub struct Handler {
    port: u16,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>
}

impl Handler {
    pub fn new<N: node::Node + 'static>(self_node: N, port: u16, routers: Vec<Box<Node>>) -> Handler {
        let self_address = self_node.get_address();
        let routing_table = routing_table::RoutingTable::new(8, self_address, routers);

        Handler {
            port: port,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new()
        }
    }

    pub fn run(mut self) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let loop_channel = event_loop.channel();

        create_incoming_udp_channel(self.port, loop_channel.clone());
        loop_channel.send(OneshotTask::StartBootstrap).unwrap();
        event_loop.run(&mut self).unwrap();
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming;
        use messages::incoming::*;
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();
        println!("Routing table: {:?}", self.routing_table);

        match message {
            Message::Query(transaction_id, query) => {
                match query {
                    Query::FindNode(origin, target) => {
                        {
                            let nodes: Vec<&Box<node::Node>> = self.routing_table.nearest_to(&target);
                            let response = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                nodes);
                            origin.send(response);
                        }

                        self.routing_table.insert(origin).unwrap();
                    }
                }
            }
            Message::Response(transaction_id, response) => {
                match response {
                    Response::FindNode(origin, mut nodes) => {
                        let mut encounted_new_node = false;
                        let mut tail = vec![origin];
                        for node in nodes.drain(..).chain(tail.drain(..)) {
                            match self.routing_table.insert(node) {
                                Ok(InsertOutcome::Inserted) => { encounted_new_node = true; }
                                _ => { }
                            }
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                if encounted_new_node {
                                    // Continue botstrapping
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.status = Status::Idle;
                                }
                            }
                            _ => { }
                        }
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        let transaction_id = self.find_self();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn find_self(&mut self) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            self.self_node.get_address());
        if let Some(node) = self.routing_table.nearest().get(0) {
            node.send(query);
        }
        transaction_id
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.start_bootstrap(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.continue_bootstrap(event_loop)
        }
    }
}

fn create_incoming_udp_channel(port: u16, sender: mio::Sender<OneshotTask>) {
    use std::net::UdpSocket;
    thread::spawn(move || {
        let address = ("0.0.0.0", port);
        let socket = UdpSocket::bind(address).unwrap();
        loop {
            let mut buf = [0; 4096];
            match socket.recv_from(&mut buf) {
                Ok((size, _src)) => {
                    sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect())).unwrap();
                }
                Err(e) => panic!("Error receiving from server: {}", e)
            }
        }
    });
}
<|endoftext|>


<commit_before>//! Option parsing and management.
//!
//! Use the `Options::parse()` function to get the program's configuration,
//! as parsed from the commandline.
//!
//! # Examples
//!
//! ```skip
//! let opts = Options::parse();
//! println!("{:?}", opts);
//! ```

use clap::{self, App, Arg, AppSettings};
use self::super::Algorithm;
use std::path::PathBuf;
use std::str::FromStr;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// Directory to hach/verify. Default: `"."`
    pub dir: PathBuf,
    /// Hashing algorithm to use. Default: `"SHA1"`
    pub algorithm: Algorithm,
    /// Whether to verify or create checksums. Default: yes
    pub verify: bool,
    /// Max recursion depth. Default: `LastLevel`
    pub depth: DepthSetting,
    /// In-/Output filename. Default: `"./INFERRED_FROM_DIRECTORY.hash"`
    pub file: (String, PathBuf),
}

/// Representation of how deep recursion should be.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum DepthSetting {
    /// Infinite allowed recursion, `-1` in argument
    Infinite,
    /// Last recursion level, go no further. `0` in argument. The default
    LastLevel,
    /// Another `N` recursion levels remaining.
    ///
    /// Entering a value `<= 0` here yields unspecified behaviour.
    NRemaining(u32),
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = App::new("checksums")
            .setting(AppSettings::ColoredHelp)
            .version(crate_version!())
            .author(crate_authors!())
            .about("Tool for making/verifying checksums of directory trees")
            .args(&[Arg::from_usage("[DIRECTORY] 'Directory to hash/verify'").default_value(".").validator(Options::directory_validator),
                    Arg::from_usage("--algorithm=[algorithm] -a 'Hashing algorithm to use. {n}\
                                     Supported algorithms: SHA{1,2-{256,512},3-{256,512}}, BLAKE{,2}, CRC{64,32,16,8}, MD5, XOR8'")
                        .next_line_help(true)
                        .default_value("SHA1")
                        .validator(Options::algorithm_validator),
                    Arg::from_usage("--create -c 'Make checksums'").overrides_with("verify"),
                    Arg::from_usage("--verify -v 'Verify checksums (default)'").overrides_with("create"),
                    Arg::from_usage("--depth=[depth] -d 'Max recursion depth. `-1` for infinite.'. Default: don't recurse")
                        .validator(Options::depth_validator)
                        .overrides_with("recursive"),
                    Arg::from_usage("--recursive -r 'Infinite recursion depth.'").overrides_with("depth"),
                    Arg::from_usage("--file=[file] -f 'File with hashes to be read/created'").validator(Options::file_validator),
                    Arg::from_usage("--force 'Override output file'")])
            .get_matches();

        let dir = fs::canonicalize(matches.value_of("DIRECTORY").unwrap()).unwrap();
        let verify = !matches.is_present("create");
        let file = Options::file_process(matches.value_of("file"), &dir);

        if file.1.exists() && !verify && !matches.is_present("force") {
            clap::Error {
                    message: "The output file exists and was not overridden to prevent data loss.\n\
                              Pass the --force option to suppress this error."
                        .to_string(),
                    kind: clap::ErrorKind::MissingRequiredArgument,
                    info: None,
                }
                .exit();
        }

        Options {
            dir: dir,
            algorithm: Algorithm::from_str(matches.value_of("algorithm").unwrap()).unwrap(),
            verify: verify,
            depth: if matches.is_present("recursive") {
                DepthSetting::Infinite
            } else {
                DepthSetting::from_str(matches.value_of("depth").unwrap_or("0")).unwrap()
            },
            file: file,
        }
    }

    fn algorithm_validator(s: String) -> Result<(), String> {
        Algorithm::from_str(&s).map(|_| ())
    }

    fn directory_validator(s: String) -> Result<(), String> {
        fs::canonicalize(s).map_err(|e| format!("directory: {}", e.to_string())).and_then(|p| {
            if p.is_file() {
                Err("DIRECTORY cannot be a file.".to_string())
            } else {
                Ok(())
            }
        })
    }

    fn depth_validator(s: String) -> Result<(), String> {
        DepthSetting::from_str(&s).map(|_| ())
    }

    fn file_validator(s: String) -> Result<(), String> {
        let mut buf = PathBuf::from(s);
        if buf.exists() && buf.is_dir() {
            Err("file exists and is a directory".to_string())
        } else {
            buf.pop();

            // Handle pathless filename
            if buf.as_os_str().is_empty() {
                Ok(())
            } else {
                buf.canonicalize().map(|_| ()).map_err(|e| format!("file: {}", e.to_string()))
            }
        }
    }

    fn file_process(file: Option<&str>, dir: &PathBuf) -> (String, PathBuf) {
        match file {
            Some(file) => {
                let mut file = PathBuf::from(file);
                let file_name = file.file_name().unwrap().to_os_string();

                file.pop();
                // Handle pathless filename
                if file.as_os_str().is_empty() {
                    file.push(".");
                }

                (file_name.to_str().unwrap().to_string(),
                 file.canonicalize()
                    .map(|mut p| {
                        p.push(file_name);
                        p
                    })
                    .unwrap())
            }
            None => {
                let mut file = dir.clone();
                file.push(dir.file_name().unwrap());
                file.set_extension("hash");
                (file.file_name().unwrap().to_str().unwrap().to_string(), file)
            }
        }
    }
}

impl DepthSetting {
    /// Check if this depth can go one level deeper.
    ///
    /// If so, `next_level()` will return `Some`, otherwise, `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// assert!(DepthSetting::Infinite.can_recurse());
    ///
    /// assert_false!(DepthSetting::LastLevel.can_recurse());
    ///
    /// assert!(DepthSetting::NRemaining(1).can_recurse());
    /// assert!(DepthSetting::NRemaining(100).can_recurse());
    /// ```
    pub fn can_recurse(&self) -> bool {
        match self {
            &DepthSetting::Infinite |
            &DepthSetting::NRemaining(_) => true,
            &DepthSetting::LastLevel => false,
        }
    }

    /// Get the next recursion level, if one exists.
    ///
    /// The next recursion level does *not* exist only for `LastLevel`.
    ///
    /// # Examples
    ///
    /// ```
    /// // Normally you'd acquire from elsewhere.
    /// let depth = DepthSetting::NRemaining(1);
    ///
    /// if let Some(next) = depth.next_level() {
    ///     // Recurse into the next level...
    ///     assert_eq!(next, DepthSetting::LastLevel);
    /// }
    /// ```
    pub fn next_level(&self) -> Option<Self> {
        match self {
            &DepthSetting::Infinite => Some(DepthSetting::Infinite),
            &DepthSetting::NRemaining(n) => Some(Self::from(n as i32 - 1)),
            &DepthSetting::LastLevel => None,
        }
    }
}

impl FromStr for DepthSetting {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        i32::from_str(&s).map(DepthSetting::from).map_err(|e| e.to_string())
    }
}

impl From<i32> for DepthSetting {
    fn from(n: i32) -> Self {
        if n < 0 {
            DepthSetting::Infinite
        } else if n > 0 {
            DepthSetting::NRemaining(n as u32)
        } else {
            DepthSetting::LastLevel
        }
    }
}

#[cfg(test)]
mod tests {
    mod depth {
        use self::super::super::DepthSetting;
        use std::str::FromStr;

        mod can_recurse {
            use self::super::super::super::DepthSetting;

            #[test]
            fn doctest() {
                assert!(DepthSetting::Infinite.can_recurse());

                assert!(!DepthSetting::LastLevel.can_recurse());

                assert!(DepthSetting::NRemaining(1).can_recurse());
                assert!(DepthSetting::NRemaining(100).can_recurse());
            }
        }

        mod next_level {
            use self::super::super::super::DepthSetting;

            #[test]
            fn doctest() {
                // Normally you'd acquire from elsewhere.
                let depth = DepthSetting::NRemaining(1);

                if let Some(next) = depth.next_level() {
                    // Recurse into the next level...
                    assert_eq!(next, DepthSetting::LastLevel);
                }
            }

            #[test]
            fn infinite() {
                assert_eq!(DepthSetting::Infinite.next_level(), Some(DepthSetting::Infinite));
            }

            #[test]
            fn last_level() {
                assert_eq!(DepthSetting::LastLevel.next_level(), None);
            }

            #[test]
            fn nremaining() {
                assert_eq!(DepthSetting::NRemaining(1).next_level(), Some(DepthSetting::LastLevel));

                assert_eq!(DepthSetting::NRemaining(2).next_level(), Some(DepthSetting::NRemaining(1)));
                assert_eq!(DepthSetting::NRemaining(100).next_level(), Some(DepthSetting::NRemaining(99)));
            }
        }

        #[test]
        fn from_str() {

            for p in &[("-1", DepthSetting::Infinite),
                       ("-100", DepthSetting::Infinite),
                       ("0", DepthSetting::LastLevel),
                       ("1", DepthSetting::NRemaining(1)),
                       ("2", DepthSetting::NRemaining(2)),
                       ("100", DepthSetting::NRemaining(100))] {
                assert_eq!(DepthSetting::from_str(p.0).unwrap(), p.1);
            }
        }

        #[test]
        fn from_str_bad() {
            for s in &["a234", "1231d"] {
                DepthSetting::from_str(s).unwrap_err();
            }
        }
    }
}
<commit_msg>Fix output file name generation in FS root. Closes #1<commit_after>//! Option parsing and management.
//!
//! Use the `Options::parse()` function to get the program's configuration,
//! as parsed from the commandline.
//!
//! # Examples
//!
//! ```skip
//! let opts = Options::parse();
//! println!("{:?}", opts);
//! ```

use clap::{self, App, Arg, AppSettings};
use self::super::Algorithm;
use std::path::PathBuf;
use std::str::FromStr;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// Directory to hach/verify. Default: `"."`
    pub dir: PathBuf,
    /// Hashing algorithm to use. Default: `"SHA1"`
    pub algorithm: Algorithm,
    /// Whether to verify or create checksums. Default: yes
    pub verify: bool,
    /// Max recursion depth. Default: `LastLevel`
    pub depth: DepthSetting,
    /// In-/Output filename. Default: `"./INFERRED_FROM_DIRECTORY.hash"`
    pub file: (String, PathBuf),
}

/// Representation of how deep recursion should be.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum DepthSetting {
    /// Infinite allowed recursion, `-1` in argument
    Infinite,
    /// Last recursion level, go no further. `0` in argument. The default
    LastLevel,
    /// Another `N` recursion levels remaining.
    ///
    /// Entering a value `<= 0` here yields unspecified behaviour.
    NRemaining(u32),
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = App::new("checksums")
            .setting(AppSettings::ColoredHelp)
            .version(crate_version!())
            .author(crate_authors!())
            .about("Tool for making/verifying checksums of directory trees")
            .args(&[Arg::from_usage("[DIRECTORY] 'Directory to hash/verify'").default_value(".").validator(Options::directory_validator),
                    Arg::from_usage("--algorithm=[algorithm] -a 'Hashing algorithm to use. {n}\
                                     Supported algorithms: SHA{1,2-{256,512},3-{256,512}}, BLAKE{,2}, CRC{64,32,16,8}, MD5, XOR8'")
                        .next_line_help(true)
                        .default_value("SHA1")
                        .validator(Options::algorithm_validator),
                    Arg::from_usage("--create -c 'Make checksums'").overrides_with("verify"),
                    Arg::from_usage("--verify -v 'Verify checksums (default)'").overrides_with("create"),
                    Arg::from_usage("--depth=[depth] -d 'Max recursion depth. `-1` for infinite.'. Default: don't recurse")
                        .validator(Options::depth_validator)
                        .overrides_with("recursive"),
                    Arg::from_usage("--recursive -r 'Infinite recursion depth.'").overrides_with("depth"),
                    Arg::from_usage("--file=[file] -f 'File with hashes to be read/created'").validator(Options::file_validator),
                    Arg::from_usage("--force 'Override output file'")])
            .get_matches();

        let dir = fs::canonicalize(matches.value_of("DIRECTORY").unwrap()).unwrap();
        let verify = !matches.is_present("create");
        let file = Options::file_process(matches.value_of("file"), &dir);

        if file.1.exists() && !verify && !matches.is_present("force") {
            clap::Error {
                    message: "The output file exists and was not overridden to prevent data loss.\n\
                              Pass the --force option to suppress this error."
                        .to_string(),
                    kind: clap::ErrorKind::MissingRequiredArgument,
                    info: None,
                }
                .exit();
        }

        Options {
            dir: dir,
            algorithm: Algorithm::from_str(matches.value_of("algorithm").unwrap()).unwrap(),
            verify: verify,
            depth: if matches.is_present("recursive") {
                DepthSetting::Infinite
            } else {
                DepthSetting::from_str(matches.value_of("depth").unwrap_or("0")).unwrap()
            },
            file: file,
        }
    }

    fn algorithm_validator(s: String) -> Result<(), String> {
        Algorithm::from_str(&s).map(|_| ())
    }

    fn directory_validator(s: String) -> Result<(), String> {
        fs::canonicalize(s).map_err(|e| format!("directory: {}", e.to_string())).and_then(|p| {
            if p.is_file() {
                Err("DIRECTORY cannot be a file.".to_string())
            } else {
                Ok(())
            }
        })
    }

    fn depth_validator(s: String) -> Result<(), String> {
        DepthSetting::from_str(&s).map(|_| ())
    }

    fn file_validator(s: String) -> Result<(), String> {
        let mut buf = PathBuf::from(s);
        if buf.exists() && buf.is_dir() {
            Err("file exists and is a directory".to_string())
        } else {
            buf.pop();

            // Handle pathless filename
            if buf.as_os_str().is_empty() {
                Ok(())
            } else {
                buf.canonicalize().map(|_| ()).map_err(|e| format!("file: {}", e.to_string()))
            }
        }
    }

    fn file_process(file: Option<&str>, dir: &PathBuf) -> (String, PathBuf) {
        match file {
            Some(file) => {
                let mut file = PathBuf::from(file);
                let file_name = file.file_name().unwrap().to_os_string();

                file.pop();
                // Handle pathless filename
                if file.as_os_str().is_empty() {
                    file.push(".");
                }

                (file_name.to_str().unwrap().to_string(),
                 file.canonicalize()
                    .map(|mut p| {
                        p.push(file_name);
                        p
                    })
                    .unwrap())
            }
            None => {
                let mut file = dir.clone();
                match dir.file_name() {
                    Some(fname) => file.push(fname),
                    None => file.push(Options::root_fname(dir)),
                }
                file.set_extension("hash");

                (file.file_name().unwrap().to_str().unwrap().to_string(), file)
            }
        }
    }

    #[cfg(windows)]
    fn root_fname(dir: &PathBuf) -> String {
        let mut dir = dir.as_os_str().to_str().unwrap().to_string();

        dir[dir.len() - 3..dir.len() - 2].to_string()
    }

    #[cfg(not(windows))]
    fn root_fname(_: &PathBuf) -> String {
        "root".to_string()
    }
}

impl DepthSetting {
    /// Check if this depth can go one level deeper.
    ///
    /// If so, `next_level()` will return `Some`, otherwise, `None`.
    ///
    /// # Examples
    ///
    /// ```
    /// assert!(DepthSetting::Infinite.can_recurse());
    ///
    /// assert_false!(DepthSetting::LastLevel.can_recurse());
    ///
    /// assert!(DepthSetting::NRemaining(1).can_recurse());
    /// assert!(DepthSetting::NRemaining(100).can_recurse());
    /// ```
    pub fn can_recurse(&self) -> bool {
        match self {
            &DepthSetting::Infinite |
            &DepthSetting::NRemaining(_) => true,
            &DepthSetting::LastLevel => false,
        }
    }

    /// Get the next recursion level, if one exists.
    ///
    /// The next recursion level does *not* exist only for `LastLevel`.
    ///
    /// # Examples
    ///
    /// ```
    /// // Normally you'd acquire from elsewhere.
    /// let depth = DepthSetting::NRemaining(1);
    ///
    /// if let Some(next) = depth.next_level() {
    ///     // Recurse into the next level...
    ///     assert_eq!(next, DepthSetting::LastLevel);
    /// }
    /// ```
    pub fn next_level(&self) -> Option<Self> {
        match self {
            &DepthSetting::Infinite => Some(DepthSetting::Infinite),
            &DepthSetting::NRemaining(n) => Some(Self::from(n as i32 - 1)),
            &DepthSetting::LastLevel => None,
        }
    }
}

impl FromStr for DepthSetting {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        i32::from_str(&s).map(DepthSetting::from).map_err(|e| e.to_string())
    }
}

impl From<i32> for DepthSetting {
    fn from(n: i32) -> Self {
        if n < 0 {
            DepthSetting::Infinite
        } else if n > 0 {
            DepthSetting::NRemaining(n as u32)
        } else {
            DepthSetting::LastLevel
        }
    }
}

#[cfg(test)]
mod tests {
    mod depth {
        use self::super::super::DepthSetting;
        use std::str::FromStr;

        mod can_recurse {
            use self::super::super::super::DepthSetting;

            #[test]
            fn doctest() {
                assert!(DepthSetting::Infinite.can_recurse());

                assert!(!DepthSetting::LastLevel.can_recurse());

                assert!(DepthSetting::NRemaining(1).can_recurse());
                assert!(DepthSetting::NRemaining(100).can_recurse());
            }
        }

        mod next_level {
            use self::super::super::super::DepthSetting;

            #[test]
            fn doctest() {
                // Normally you'd acquire from elsewhere.
                let depth = DepthSetting::NRemaining(1);

                if let Some(next) = depth.next_level() {
                    // Recurse into the next level...
                    assert_eq!(next, DepthSetting::LastLevel);
                }
            }

            #[test]
            fn infinite() {
                assert_eq!(DepthSetting::Infinite.next_level(), Some(DepthSetting::Infinite));
            }

            #[test]
            fn last_level() {
                assert_eq!(DepthSetting::LastLevel.next_level(), None);
            }

            #[test]
            fn nremaining() {
                assert_eq!(DepthSetting::NRemaining(1).next_level(), Some(DepthSetting::LastLevel));

                assert_eq!(DepthSetting::NRemaining(2).next_level(), Some(DepthSetting::NRemaining(1)));
                assert_eq!(DepthSetting::NRemaining(100).next_level(), Some(DepthSetting::NRemaining(99)));
            }
        }

        #[test]
        fn from_str() {

            for p in &[("-1", DepthSetting::Infinite),
                       ("-100", DepthSetting::Infinite),
                       ("0", DepthSetting::LastLevel),
                       ("1", DepthSetting::NRemaining(1)),
                       ("2", DepthSetting::NRemaining(2)),
                       ("100", DepthSetting::NRemaining(100))] {
                assert_eq!(DepthSetting::from_str(p.0).unwrap(), p.1);
            }
        }

        #[test]
        fn from_str_bad() {
            for s in &["a234", "1231d"] {
                DepthSetting::from_str(s).unwrap_err();
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    completion::{
        completion_context::CompletionContext,
        completion_item::{Builder, CompletionKind, Completions},
    },
    CompletionItem,
};
use ra_syntax::{ast::AstNode, TextRange};
use ra_text_edit::TextEditBuilder;

fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
    let edit = {
        let receiver_range = ctx.dot_receiver.expect("no receiver available").syntax().range();
        let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
        let mut builder = TextEditBuilder::default();
        builder.replace(delete_range, snippet.to_string());
        builder.finish()
    };
    CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
        .detail(detail)
        .snippet_edit(edit)
}

pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some(dot_receiver) = ctx.dot_receiver {
        let receiver_text = dot_receiver.syntax().text().to_string();
        postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
        postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
        postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);
        postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
            .add_to(acc);
        postfix_snippet(
            ctx,
            "match",
            "match expr {}",
            &format!("match {} {{\n    ${{1:_}} => {{$0\\}},\n}}", receiver_text),
        )
        .add_to(acc);
        postfix_snippet(
            ctx,
            "while",
            "while expr {}",
            &format!("while {} {{\n$0\n}}", receiver_text),
        )
        .add_to(acc);
        postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);
        postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
            .add_to(acc);
    }
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot_matches;

    fn do_postfix_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Postfix)
    }

    #[test]
    fn postfix_completion_works_for_trivial_path_expression() {
        assert_debug_snapshot_matches!(
            do_postfix_completion(
                r#"
                fn main() {
                    let bar = "a";
                    bar.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "Box::new(bar)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "dbg!(bar)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "if",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "if bar {$0}",
        detail: "if expr {}",
    },
    CompletionItem {
        label: "match",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "match bar {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "!bar",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "&bar",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "&mut bar",
        detail: "&mut expr",
    },
    CompletionItem {
        label: "while",
        source_range: [88; 88),
        delete: [84; 88),
        insert: "while bar {\n$0\n}",
        detail: "while expr {}",
    },
]"###
        );
    }
}
<commit_msg>Restrict some postfix completions to bool and unknown expr.<commit_after>use crate::{
    completion::{
        completion_context::CompletionContext,
        completion_item::{Builder, CompletionKind, Completions},
    },
    CompletionItem,
};
use hir::{Ty, TypeCtor};
use ra_syntax::{ast::AstNode, TextRange};
use ra_text_edit::TextEditBuilder;

fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
    let edit = {
        let receiver_range = ctx.dot_receiver.expect("no receiver available").syntax().range();
        let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
        let mut builder = TextEditBuilder::default();
        builder.replace(delete_range, snippet.to_string());
        builder.finish()
    };
    CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
        .detail(detail)
        .snippet_edit(edit)
}

fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
    if let Some(ty) = ty {
        match ty {
            Ty::Apply(at) => match at.ctor {
                TypeCtor::Bool => true,
                _ => false,
            },
            Ty::Unknown => true,
            _ => false,
        }
    } else {
        true
    }
}

pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some(dot_receiver) = ctx.dot_receiver {
        let receiver_text = dot_receiver.syntax().text().to_string();
        let receiver_ty = ctx.analyzer.type_of(ctx.db, dot_receiver);
        if is_bool_or_unknown(receiver_ty) {
            postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
                .add_to(acc);
            postfix_snippet(
                ctx,
                "while",
                "while expr {}",
                &format!("while {} {{\n$0\n}}", receiver_text),
            )
            .add_to(acc);
        }
        postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
        postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
        postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);
        postfix_snippet(
            ctx,
            "match",
            "match expr {}",
            &format!("match {} {{\n    ${{1:_}} => {{$0\\}},\n}}", receiver_text),
        )
        .add_to(acc);
        postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);
        postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
            .add_to(acc);
    }
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot_matches;

    fn do_postfix_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Postfix)
    }

    #[test]
    fn postfix_completion_works_for_trivial_path_expression() {
        assert_debug_snapshot_matches!(
            do_postfix_completion(
                r#"
                fn main() {
                    let bar = true;
                    bar.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "Box::new(bar)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "dbg!(bar)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "if",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "if bar {$0}",
        detail: "if expr {}",
    },
    CompletionItem {
        label: "match",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "match bar {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "!bar",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "&bar",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "&mut bar",
        detail: "&mut expr",
    },
    CompletionItem {
        label: "while",
        source_range: [89; 89),
        delete: [85; 89),
        insert: "while bar {\n$0\n}",
        detail: "while expr {}",
    },
]"###
        );
    }

    #[test]
    fn some_postfix_completions_ignored() {
        assert_debug_snapshot_matches!(
            do_postfix_completion(
                r#"
                fn main() {
                    let bar: u8 = 12;
                    bar.<|>
                }
                "#,
            ),
            @r###"[
    CompletionItem {
        label: "box",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "Box::new(bar)",
        detail: "Box::new(expr)",
    },
    CompletionItem {
        label: "dbg",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "dbg!(bar)",
        detail: "dbg!(expr)",
    },
    CompletionItem {
        label: "match",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "match bar {\n    ${1:_} => {$0\\},\n}",
        detail: "match expr {}",
    },
    CompletionItem {
        label: "not",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "!bar",
        detail: "!expr",
    },
    CompletionItem {
        label: "ref",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "&bar",
        detail: "&expr",
    },
    CompletionItem {
        label: "refm",
        source_range: [91; 91),
        delete: [87; 91),
        insert: "&mut bar",
        detail: "&mut expr",
    },
]"###
        );
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};

/// Each remote notification includes a payload.
/// The payload contains information about how the system should alert the user as well
/// as any custom data you provide.
pub struct Payload<'a> {
    pub aps: APS<'a>,
}

impl<'a> Payload<'a> {
    pub fn new<S>(alert: APSAlert, badge: Option<u32>, sound: S) -> Payload<'a>
        where S: Into<Cow<'a, str>>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: None,
            },
        }
    }

    pub fn new_action_notification<S>(alert: APSAlert, badge: Option<u32>, sound: S, category: S) -> Payload<'a>
        where S: Into<Cow<'a, str>>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: Some(category.into()),
            },
        }
    }

    pub fn new_silent_notification() -> Payload<'a> {
        Payload {
            aps: APS {
                alert: None,
                badge: None,
                sound: None,
                content_available: Some(1),
                category: None,
            },
        }
    }

    pub fn to_string(&self) -> String {
        self.to_json().to_string()
    }

    pub fn len(&self) -> usize {
        self.to_string().len()
    }
}

impl<'a> ToJson for Payload<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("aps".to_string(), self.aps.to_json());
        Json::Object(d)
    }
}

/// The APS can contain one or more properties that specify the following user notification types:
/// - an alert message to display to the user
/// - a number to badge the app icon with
/// - a sound to play
pub struct APS<'a> {
    /// If this property is included, the system displays a standard alert or a banner,
    /// based on the user’s setting.
    pub alert: Option<APSAlert>,

    /// The number to display as the badge of the app icon.
    pub badge: Option<u32>,

    /// The name of a sound file in the app bundle or in the Library/Sounds folder of
    /// the app’s data container.
    pub sound: Option<Cow<'a, str>>,

    /// Provide this key with a value of 1 to indicate that new content is available.
    pub content_available: Option<u32>,

    /// Provide this key with a string value that represents the identifier property.
    pub category: Option<Cow<'a, str>>,
}

impl<'a> ToJson for APS<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.alert {
            Some(APSAlert::Plain(ref s)) => {
                d.insert("alert".to_string(), s.to_json());
            }
            Some(APSAlert::Localized(ref l)) => {
                d.insert("alert".to_string(), l.to_json());
            }
            None => {}
        };
        if let Some(ref badge) = self.badge {
            d.insert("badge".to_string(), badge.to_json());
        }
        if let Some(ref sound) = self.sound {
            d.insert("sound".to_string(), sound.to_json());
        }
        if let Some(ref content_available) = self.content_available {
            d.insert("content-available".to_string(), content_available.to_json());
        }
        if let Some(ref category) = self.category {
            d.insert("category".to_string(), category.to_json());
        }
        Json::Object(d)
    }
}

/// Can specify a string or a dictionary as the value of alert.
pub enum APSAlert {
    Plain(String),
    Localized(APSLocalizedAlert),
}

/// Child properties of the alert property.
pub struct APSLocalizedAlert {
    /// A short string describing the purpose of the notification
    pub title: String,

    /// The text of the alert message.
    pub body: String,

    /// The key to a title string in the Localizable.strings file for the current localization.
    pub title_loc_key: Option<String>,

    /// Variable string values to appear in place of the format specifiers in title-loc-key.
    pub title_loc_args: Option<Vec<String>>,

    /// If a string is specified, the system displays an alert that includes the Close and View buttons.
    pub action_loc_key: Option<String>,

    /// A key to an alert-message string in a Localizable.strings file for the current localization.
    pub loc_key: String,

    /// Variable string values to appear in place of the format specifiers in loc-key.
    pub loc_args: Vec<String>,

    /// The filename of an image file in the app bundle.
    /// The image is used as the launch image when users tap the action button or move the action slider.
    pub launch_image: Option<String>,
}

impl ToJson for APSLocalizedAlert {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("title".to_string(), self.title.to_json());
        d.insert("body".to_string(), self.body.to_json());
        d.insert("title-loc-key".to_string(), match self.title_loc_key {
            Some(ref k) => k.to_json(),
            None => Json::Null,
        });
        d.insert("title-loc-args".to_string(), match self.title_loc_args {
            Some(ref a) => a.to_json(),
            None => Json::Null,
        });
        d.insert("action-loc-key".to_string(), match self.action_loc_key {
            Some(ref k) => k.to_json(),
            None => Json::Null,
        });
        d.insert("loc-key".to_string(), self.loc_key.to_json());
        d.insert("loc-args".to_string(), self.loc_args.to_json());
        if let Some(ref i) = self.launch_image {
            d.insert("launch-image".to_string(), i.to_json());
        }
        Json::Object(d)
    }
}
<commit_msg>Make some of the payload values optional, add category field<commit_after>use std::borrow::Cow;
use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};

/// Each remote notification includes a payload.
/// The payload contains information about how the system should alert the user as well
/// as any custom data you provide.
pub struct Payload<'a> {
    pub aps: APS<'a>,
}

pub struct APS {
    pub alert: Option<APSAlert>,

    // The number to display as the badge of the app icon.
    pub badge: Option<u32>,

    // The name of a sound file in the app bundle or in the Library/Sounds folder of
    // the app’s data container.
    pub sound: Option<String>,

    // Provide this key with a value of 1 to indicate that new content is available.
    pub content_available: Option<u32>,

    // Provide this key with a string value that represents the identifier property.
    pub category: Option<String>,
}

pub enum APSAlert {
    Plain(String),
    Localized(APSLocalizedAlert),
}

pub struct APSLocalizedAlert {
    pub title: String,
    pub body: String,
    pub title_loc_key: Option<String>,
    pub title_loc_args: Option<Vec<String>>,
    pub action_loc_key: Option<String>,
    pub loc_key: String,
    pub loc_args: Vec<String>,
    pub launch_image: Option<String>,
}

impl Payload {
    pub fn new<S>(alert: APSAlert, badge: u32, sound: S, category: Option<String>) -> Payload
        where S: Into<String>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: category,
            },
        }
    }

    pub fn new_action_notification<S>(alert: APSAlert, badge: Option<u32>, sound: S, category: S) -> Payload<'a>
        where S: Into<Cow<'a, str>>
    {
        Payload {
            aps: APS {
                alert: Some(alert),
                badge: badge,
                sound: Some(sound.into()),
                content_available: None,
                category: Some(category.into()),
            },
        }
    }

    pub fn new_silent_notification() -> Payload<'a> {
        Payload {
            aps: APS {
                alert: None,
                badge: None,
                sound: None,
                content_available: Some(1),
                category: None,
            },
        }
    }

    pub fn to_string(&self) -> String {
        self.to_json().to_string()
    }

    pub fn len(&self) -> usize {
        self.to_string().len()
    }
}

impl<'a> ToJson for Payload<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("aps".to_string(), self.aps.to_json());
        Json::Object(d)
    }
}

/// The APS can contain one or more properties that specify the following user notification types:
/// - an alert message to display to the user
/// - a number to badge the app icon with
/// - a sound to play
pub struct APS<'a> {
    /// If this property is included, the system displays a standard alert or a banner,
    /// based on the user’s setting.
    pub alert: Option<APSAlert>,

    /// The number to display as the badge of the app icon.
    pub badge: Option<u32>,

    /// The name of a sound file in the app bundle or in the Library/Sounds folder of
    /// the app’s data container.
    pub sound: Option<Cow<'a, str>>,

    /// Provide this key with a value of 1 to indicate that new content is available.
    pub content_available: Option<u32>,

    /// Provide this key with a string value that represents the identifier property.
    pub category: Option<Cow<'a, str>>,
}

impl<'a> ToJson for APS<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self.alert {
            Some(APSAlert::Plain(ref s)) => {
                d.insert("alert".to_string(), s.to_json());
            }
            Some(APSAlert::Localized(ref l)) => {
                d.insert("alert".to_string(), l.to_json());
            }
            None => {}
        };
        if let Some(ref badge) = self.badge {
            d.insert("badge".to_string(), badge.to_json());
        }
        if let Some(ref sound) = self.sound {
            d.insert("sound".to_string(), sound.to_json());
        }
        if let Some(ref content_available) = self.content_available {
            d.insert("content-available".to_string(), content_available.to_json());
        }
        if let Some(ref category) = self.category {
            d.insert("category".to_string(), category.to_json());
        }
        Json::Object(d)
    }
}

/// Can specify a string or a dictionary as the value of alert.
pub enum APSAlert {
    Plain(String),
    Localized(APSLocalizedAlert),
}

/// Child properties of the alert property.
pub struct APSLocalizedAlert {
    /// A short string describing the purpose of the notification
    pub title: String,

    /// The text of the alert message.
    pub body: String,

    /// The key to a title string in the Localizable.strings file for the current localization.
    pub title_loc_key: Option<String>,

    /// Variable string values to appear in place of the format specifiers in title-loc-key.
    pub title_loc_args: Option<Vec<String>>,

    /// If a string is specified, the system displays an alert that includes the Close and View buttons.
    pub action_loc_key: Option<String>,

    /// A key to an alert-message string in a Localizable.strings file for the current localization.
    pub loc_key: String,

    /// Variable string values to appear in place of the format specifiers in loc-key.
    pub loc_args: Vec<String>,

    /// The filename of an image file in the app bundle.
    /// The image is used as the launch image when users tap the action button or move the action slider.
    pub launch_image: Option<String>,
}

impl ToJson for APSLocalizedAlert {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();

        d.insert("title".to_string(), self.title.to_json());
        d.insert("body".to_string(), self.body.to_json());

        if let Some(ref title_loc_key) = self.title_loc_key {
            d.insert("title-loc-key".to_string(), title_loc_key.to_json());
        } else {
            d.insert("title-loc-key".to_string(), Json::Null);
        }

        if let Some(ref title_loc_args) = self.title_loc_args {
            d.insert("title-loc-args".to_string(), title_loc_args.to_json());
        } else {
            d.insert("title-loc-args".to_string(), Json::Null);
        }

        if let Some(ref action_loc_key) = self.action_loc_key {
            d.insert("action-loc-key".to_string(), action_loc_key.to_json());
        } else {
            d.insert("action-loc-key".to_string(), Json::Null);
        }

        d.insert("loc-key".to_string(), self.loc_key.to_json());
        d.insert("loc-args".to_string(), self.loc_args.to_json());

        if let Some(ref launch_image) = self.launch_image {
            d.insert("launch-image".to_string(), launch_image.to_json());
        }

        Json::Object(d)
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::{Decodable, Decoder};
use std::fs::File;
use std::path::Path;
use toml;

use Result;

pub struct Details(pub toml::Value);

pub trait Detailable {
    fn set_details<'l>(&mut self, Option<&'l toml::Value>);
    fn get_details<'l>(&'l self) -> Option<&'l toml::Value>;

    fn lookup(&self, name: &str) -> Option<String> {
        self.get_details().and_then(|toml| {
            match toml.lookup(name) {
                Some(&toml::Value::String(ref string)) => Some(string.clone()),
                _ => None,
            }
        })
    }
}

#[derive(RustcDecodable)]
pub struct Config {
    pub time: Option<Time>,
    pub power: Option<Power>,
    pub temperature: Option<Temperature>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Time {
    pub period: Option<f64>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Power {
    pub sources: Option<Vec<Source>>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Temperature {
    pub stack: Option<String>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Source {
    pub name: Option<String>,
    pub path: Option<String>,
    pub details: Option<Details>,
}

impl Config {
    pub fn new(path: &Path) -> Result<Config> {
        use std::io::Read;

        let mut contents = String::new();
        ok!(ok!(File::open(path)).read_to_string(&mut contents));

        let config = match toml::Parser::new(&contents).parse() {
            Some(root) => {
                let mut decoder = toml::Decoder::new(toml::Value::Table(root));
                let mut config: Config = ok!(Decodable::decode(&mut decoder));
                config.set_details(decoder.toml.as_ref());
                config
            },
            _ => raise!("failed to parse the configuration file"),
        };

        Ok(config)
    }
}

impl Decodable for Details {
    #[inline]
    fn decode<D: Decoder>(_: &mut D) -> ::std::result::Result<Self, D::Error> {
        panic!("“details” is a reserved keyword");
    }
}

macro_rules! detailable(
    ($kind:ty, [$($scalar:ident),*], [$($vector:ident),*]) => (
        impl Detailable for $kind {
            fn set_details<'l>(&mut self, toml: Option<&'l toml::Value>) {
                self.details = toml.and_then(|toml| {
                    $(
                        if let Some(ref mut child) = self.$scalar {
                            child.set_details(toml.lookup(stringify!($scalar)));
                        }
                    )*
                    $(
                        if let Some(ref mut children) = self.$vector {
                            match toml.lookup(stringify!($vector)) {
                                Some(&toml::Value::Array(ref array)) => {
                                    for (child, toml) in children.iter_mut().zip(array) {
                                        child.set_details(Some(toml));
                                    }
                                },
                                _ => {},
                            }
                        }
                    )*
                    Some(Details(toml.clone()))
                });
            }

            #[inline]
            fn get_details<'l>(&'l self) -> Option<&'l toml::Value> {
                self.details.as_ref().map(|details| &details.0)
            }
        }
    );
    ($kind:ty, [$($scalar:ident),*]) => (
        detailable!($kind, [$($scalar),*], []);
    );
    ($kind:ty) => (
        detailable!($kind, [], []);
    );
);

detailable!(Config, [time, power, temperature]);

detailable!(Time);

detailable!(Power, [], [sources]);
detailable!(Source);

detailable!(Temperature);
<commit_msg>Rename the functions of Detailable<commit_after>use rustc_serialize::{Decodable, Decoder};
use std::fs::File;
use std::path::Path;
use toml;

use Result;

pub struct Details(pub toml::Value);

pub trait Detailable {
    fn detail<'l>(&mut self, Option<&'l toml::Value>);
    fn liated<'l>(&'l self) -> Option<&'l toml::Value>;

    fn lookup(&self, name: &str) -> Option<String> {
        self.liated().and_then(|toml| {
            match toml.lookup(name) {
                Some(&toml::Value::String(ref string)) => Some(string.clone()),
                _ => None,
            }
        })
    }
}

#[derive(RustcDecodable)]
pub struct Config {
    pub time: Option<Time>,
    pub power: Option<Power>,
    pub temperature: Option<Temperature>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Time {
    pub period: Option<f64>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Power {
    pub sources: Option<Vec<Source>>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Temperature {
    pub stack: Option<String>,
    pub details: Option<Details>,
}

#[derive(RustcDecodable)]
pub struct Source {
    pub name: Option<String>,
    pub path: Option<String>,
    pub details: Option<Details>,
}

impl Config {
    pub fn new(path: &Path) -> Result<Config> {
        use std::io::Read;

        let mut contents = String::new();
        ok!(ok!(File::open(path)).read_to_string(&mut contents));

        let config = match toml::Parser::new(&contents).parse() {
            Some(root) => {
                let mut decoder = toml::Decoder::new(toml::Value::Table(root));
                let mut config: Config = ok!(Decodable::decode(&mut decoder));
                config.detail(decoder.toml.as_ref());
                config
            },
            _ => raise!("failed to parse the configuration file"),
        };

        Ok(config)
    }
}

impl Decodable for Details {
    #[inline]
    fn decode<D: Decoder>(_: &mut D) -> ::std::result::Result<Self, D::Error> {
        panic!("“details” is a reserved keyword");
    }
}

macro_rules! detailable(
    ($kind:ty, [$($scalar:ident),*], [$($vector:ident),*]) => (
        impl Detailable for $kind {
            fn detail<'l>(&mut self, toml: Option<&'l toml::Value>) {
                self.details = toml.and_then(|toml| {
                    $(
                        if let Some(ref mut child) = self.$scalar {
                            child.detail(toml.lookup(stringify!($scalar)));
                        }
                    )*
                    $(
                        if let Some(ref mut children) = self.$vector {
                            match toml.lookup(stringify!($vector)) {
                                Some(&toml::Value::Array(ref array)) => {
                                    for (child, toml) in children.iter_mut().zip(array) {
                                        child.detail(Some(toml));
                                    }
                                },
                                _ => {},
                            }
                        }
                    )*
                    Some(Details(toml.clone()))
                });
            }

            #[inline]
            fn liated<'l>(&'l self) -> Option<&'l toml::Value> {
                self.details.as_ref().map(|details| &details.0)
            }
        }
    );
    ($kind:ty, [$($scalar:ident),*]) => (
        detailable!($kind, [$($scalar),*], []);
    );
    ($kind:ty) => (
        detailable!($kind, [], []);
    );
);

detailable!(Config, [time, power, temperature]);

detailable!(Time);

detailable!(Power, [], [sources]);
detailable!(Source);

detailable!(Temperature);
<|endoftext|>


<commit_before>use common::document::{ContainerDocument, Document};
use geojson::Geometry;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::sync::Arc;

use super::admin::Admin;
use super::context::Context;
use super::coord::Coord;
use super::i18n_properties::I18nProperties;
use super::Members;
use crate::Address;

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(tag = "type", rename = "poi")]
pub struct Poi {
    pub id: String,
    pub label: String,
    pub name: String,
    pub coord: Coord,
    /// coord used for some geograhic queries in ES, less precise but faster than `coord`
    /// https://www.elastic.co/guide/en/elasticsearch/reference/2.4/geo-shape.html
    #[serde(skip_deserializing)]
    pub approx_coord: Option<Geometry>,
    pub administrative_regions: Vec<Arc<Admin>>,
    pub weight: f64,
    pub zip_codes: Vec<String>,
    pub poi_type: PoiType,
    pub properties: BTreeMap<String, String>,
    pub address: Option<Address>,
    #[serde(default)]
    pub country_codes: Vec<String>,

    #[serde(default)]
    pub names: I18nProperties,
    #[serde(default)]
    pub labels: I18nProperties,

    /// Distance to the coord in query.
    /// Not serialized as is because it is returned in the `Feature` object
    #[serde(default, skip)]
    pub distance: Option<u32>,

    pub context: Option<Context>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct PoiType {
    pub id: String,
    pub name: String,
}

impl From<&navitia_poi_model::PoiType> for PoiType {
    fn from(poi_type: &navitia_poi_model::PoiType) -> PoiType {
        PoiType {
            id: poi_type.id.clone(),
            name: poi_type.name.clone(),
        }
    }
}

impl Document for Poi {
    fn id(&self) -> String {
        self.id.clone()
    }
}

impl ContainerDocument for Poi {
    fn static_doc_type() -> &'static str {
        "poi"
    }
}

impl Members for Poi {
    fn label(&self) -> &str {
        &self.label
    }
    fn admins(&self) -> Vec<Arc<Admin>> {
        self.administrative_regions.clone()
    }
}

impl From<&Poi> for geojson::Geometry {
    fn from(poi: &Poi) -> Self {
        geojson::Geometry::from(poi.coord)
    }
}
<commit_msg>Fix Poi type id<commit_after>use common::document::{ContainerDocument, Document};
use geojson::Geometry;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::sync::Arc;

use super::admin::Admin;
use super::context::Context;
use super::coord::Coord;
use super::i18n_properties::I18nProperties;
use super::Members;
use crate::Address;

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(tag = "type", rename = "poi")]
pub struct Poi {
    pub id: String,
    pub label: String,
    pub name: String,
    pub coord: Coord,
    /// coord used for some geograhic queries in ES, less precise but faster than `coord`
    /// https://www.elastic.co/guide/en/elasticsearch/reference/2.4/geo-shape.html
    #[serde(skip_deserializing)]
    pub approx_coord: Option<Geometry>,
    pub administrative_regions: Vec<Arc<Admin>>,
    pub weight: f64,
    pub zip_codes: Vec<String>,
    pub poi_type: PoiType,
    pub properties: BTreeMap<String, String>,
    pub address: Option<Address>,
    #[serde(default)]
    pub country_codes: Vec<String>,

    #[serde(default)]
    pub names: I18nProperties,
    #[serde(default)]
    pub labels: I18nProperties,

    /// Distance to the coord in query.
    /// Not serialized as is because it is returned in the `Feature` object
    #[serde(default, skip)]
    pub distance: Option<u32>,

    pub context: Option<Context>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct PoiType {
    pub id: String,
    pub name: String,
}

impl From<&navitia_poi_model::PoiType> for PoiType {
    fn from(poi_type: &navitia_poi_model::PoiType) -> PoiType {
        PoiType {
            id: format!("poi_type:{}", poi_type.id),
            name: poi_type.name.clone(),
        }
    }
}

impl Document for Poi {
    fn id(&self) -> String {
        self.id.clone()
    }
}

impl ContainerDocument for Poi {
    fn static_doc_type() -> &'static str {
        "poi"
    }
}

impl Members for Poi {
    fn label(&self) -> &str {
        &self.label
    }
    fn admins(&self) -> Vec<Arc<Admin>> {
        self.administrative_regions.clone()
    }
}

impl From<&Poi> for geojson::Geometry {
    fn from(poi: &Poi) -> Self {
        geojson::Geometry::from(poi.coord)
    }
}
<|endoftext|>


<commit_before>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website <https://serde.rs/> for additional documentation and
//! usage examples.
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Bincode], a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a self-proclaimed human-friendly configuration language that ain't
//!   markup language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [RON], a Rusty Object Notation.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//!   definition.
//! - [JSON5], a superset of JSON including some productions from ES5.
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
//! - [URL] query strings, in the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
//!   Rust structs. *(deserialization only)*
//! - [S-expressions], the textual representation of code and data used by the
//!   Lisp language family.
//! - [D-Bus]'s binary wire format.
//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format.
//! - [DynamoDB Items], the format used by [rusoto_dynamodb] to transfer data to
//!   and from DynamoDB.
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/servo/bincode
//! [CBOR]: https://github.com/pyfisch/cbor
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [Avro]: https://github.com/flavray/avro-rs
//! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [Postcard]: https://github.com/jamesmunns/postcard
//! [URL]: https://docs.rs/serde_qs
//! [Envy]: https://github.com/softprops/envy
//! [Envy Store]: https://github.com/softprops/envy-store
//! [Cargo]: https://doc.rust-lang.org/cargo/reference/manifest.html
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html
//! [S-expressions]: https://github.com/rotty/lexpr-rs
//! [D-Bus]: https://docs.rs/zvariant
//! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.130")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy and clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
        unnested_or_patterns,
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
        semicolon_if_nothing_returned,
        // not available in our oldest supported compiler
        checked_conversions,
        empty_enum,
        redundant_field_names,
        redundant_static_lifetimes,
        // integer and float ser/de requires these sorts of casts
        cast_possible_truncation,
        cast_possible_wrap,
        cast_sign_loss,
        // things are often more readable this way
        cast_lossless,
        module_name_repetitions,
        option_if_let_else,
        single_match_else,
        type_complexity,
        use_self,
        zero_prefixed_literal,
        // correctly used
        enum_glob_use,
        let_underscore_drop,
        map_err_ignore,
        result_unit_err,
        wildcard_imports,
        // not practical
        needless_pass_by_value,
        similar_names,
        too_many_lines,
        // preference
        doc_markdown,
        unseparated_literal_suffix,
        // false positive
        needless_doctest_main,
        // noisy
        missing_errors_doc,
        must_use_candidate,
    )
)]
// Rustc lints.
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "alloc")]
extern crate alloc;

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(not(feature = "std"))]
        pub use core::*;
        #[cfg(feature = "std")]
        pub use std::*;
    }

    pub use self::core::{cmp, iter, mem, num, ptr, slice, str};
    pub use self::core::{f32, f64};
    pub use self::core::{i16, i32, i64, i8, isize};
    pub use self::core::{u16, u32, u64, u8, usize};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::num::Wrapping;
    pub use self::core::ops::Range;
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};
    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};
    #[cfg(feature = "std")]
    pub use std::string::{String, ToString};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;
    #[cfg(feature = "std")]
    pub use std::vec::Vec;

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;
    #[cfg(feature = "std")]
    pub use std::boxed::Box;

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::{Rc, Weak as RcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::{Rc, Weak as RcWeak};

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::sync::{Arc, Weak as ArcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::{Arc, Weak as ArcWeak};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
    #[cfg(feature = "std")]
    pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CStr, CString, OsStr, OsString};
    #[cfg(feature = "std")]
    pub use std::hash::{BuildHasher, Hash};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};
    #[cfg(feature = "std")]
    pub use std::time::{SystemTime, UNIX_EPOCH};

    #[cfg(all(feature = "std", collections_bound))]
    pub use std::collections::Bound;

    #[cfg(core_reverse)]
    pub use self::core::cmp::Reverse;

    #[cfg(ops_bound)]
    pub use self::core::ops::Bound;

    #[cfg(range_inclusive)]
    pub use self::core::ops::RangeInclusive;

    #[cfg(all(feature = "std", std_atomic))]
    pub use std::sync::atomic::{
        AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
        AtomicUsize, Ordering,
    };
    #[cfg(all(feature = "std", std_atomic64))]
    pub use std::sync::atomic::{AtomicI64, AtomicU64};

    #[cfg(any(core_duration, feature = "std"))]
    pub use self::core::time::Duration;
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

#[macro_use]
mod integer128;

pub mod de;
pub mod ser;

#[doc(inline)]
pub use de::{Deserialize, Deserializer};
#[doc(inline)]
pub use ser::{Serialize, Serializer};

// Used by generated code and doc tests. Not public API.
#[doc(hidden)]
#[path = "private/mod.rs"]
pub mod __private;

#[allow(unused_imports)]
use self::__private as export;
#[allow(unused_imports)]
use self::__private as private;

#[path = "de/seed.rs"]
mod seed;

#[cfg(not(feature = "std"))]
mod std_error;

// Re-export #[derive(Serialize, Deserialize)].
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<commit_msg>Change cbor link to new repo<commit_after>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website <https://serde.rs/> for additional documentation and
//! usage examples.
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Bincode], a compact binary format
//!   used for IPC within the Servo rendering engine.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a self-proclaimed human-friendly configuration language that ain't
//!   markup language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [RON], a Rusty Object Notation.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//!   definition.
//! - [JSON5], a superset of JSON including some productions from ES5.
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
//! - [URL] query strings, in the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
//!   Rust structs. *(deserialization only)*
//! - [S-expressions], the textual representation of code and data used by the
//!   Lisp language family.
//! - [D-Bus]'s binary wire format.
//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format.
//! - [DynamoDB Items], the format used by [rusoto_dynamodb] to transfer data to
//!   and from DynamoDB.
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/servo/bincode
//! [CBOR]: https://github.com/enarx/ciborium
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [Avro]: https://github.com/flavray/avro-rs
//! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [Postcard]: https://github.com/jamesmunns/postcard
//! [URL]: https://docs.rs/serde_qs
//! [Envy]: https://github.com/softprops/envy
//! [Envy Store]: https://github.com/softprops/envy-store
//! [Cargo]: https://doc.rust-lang.org/cargo/reference/manifest.html
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html
//! [S-expressions]: https://github.com/rotty/lexpr-rs
//! [D-Bus]: https://docs.rs/zvariant
//! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.130")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy and clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
        unnested_or_patterns,
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
        semicolon_if_nothing_returned,
        // not available in our oldest supported compiler
        checked_conversions,
        empty_enum,
        redundant_field_names,
        redundant_static_lifetimes,
        // integer and float ser/de requires these sorts of casts
        cast_possible_truncation,
        cast_possible_wrap,
        cast_sign_loss,
        // things are often more readable this way
        cast_lossless,
        module_name_repetitions,
        option_if_let_else,
        single_match_else,
        type_complexity,
        use_self,
        zero_prefixed_literal,
        // correctly used
        enum_glob_use,
        let_underscore_drop,
        map_err_ignore,
        result_unit_err,
        wildcard_imports,
        // not practical
        needless_pass_by_value,
        similar_names,
        too_many_lines,
        // preference
        doc_markdown,
        unseparated_literal_suffix,
        // false positive
        needless_doctest_main,
        // noisy
        missing_errors_doc,
        must_use_candidate,
    )
)]
// Rustc lints.
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "alloc")]
extern crate alloc;

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(not(feature = "std"))]
        pub use core::*;
        #[cfg(feature = "std")]
        pub use std::*;
    }

    pub use self::core::{cmp, iter, mem, num, ptr, slice, str};
    pub use self::core::{f32, f64};
    pub use self::core::{i16, i32, i64, i8, isize};
    pub use self::core::{u16, u32, u64, u8, usize};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::num::Wrapping;
    pub use self::core::ops::Range;
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};
    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};
    #[cfg(feature = "std")]
    pub use std::string::{String, ToString};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;
    #[cfg(feature = "std")]
    pub use std::vec::Vec;

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;
    #[cfg(feature = "std")]
    pub use std::boxed::Box;

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::{Rc, Weak as RcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::{Rc, Weak as RcWeak};

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::sync::{Arc, Weak as ArcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::{Arc, Weak as ArcWeak};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
    #[cfg(feature = "std")]
    pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CStr, CString, OsStr, OsString};
    #[cfg(feature = "std")]
    pub use std::hash::{BuildHasher, Hash};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};
    #[cfg(feature = "std")]
    pub use std::time::{SystemTime, UNIX_EPOCH};

    #[cfg(all(feature = "std", collections_bound))]
    pub use std::collections::Bound;

    #[cfg(core_reverse)]
    pub use self::core::cmp::Reverse;

    #[cfg(ops_bound)]
    pub use self::core::ops::Bound;

    #[cfg(range_inclusive)]
    pub use self::core::ops::RangeInclusive;

    #[cfg(all(feature = "std", std_atomic))]
    pub use std::sync::atomic::{
        AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
        AtomicUsize, Ordering,
    };
    #[cfg(all(feature = "std", std_atomic64))]
    pub use std::sync::atomic::{AtomicI64, AtomicU64};

    #[cfg(any(core_duration, feature = "std"))]
    pub use self::core::time::Duration;
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

#[macro_use]
mod integer128;

pub mod de;
pub mod ser;

#[doc(inline)]
pub use de::{Deserialize, Deserializer};
#[doc(inline)]
pub use ser::{Serialize, Serializer};

// Used by generated code and doc tests. Not public API.
#[doc(hidden)]
#[path = "private/mod.rs"]
pub mod __private;

#[allow(unused_imports)]
use self::__private as export;
#[allow(unused_imports)]
use self::__private as private;

#[path = "de/seed.rs"]
mod seed;

#[cfg(not(feature = "std"))]
mod std_error;

// Re-export #[derive(Serialize, Deserialize)].
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;
<|endoftext|>