<commit_before>// A variation on cares-epoll.rs
//
// Here we hide the use of epoll() behind a `Resolver` object.  We also
// transform the asynchronous c-ares interface into a synchronous one, by
// using a std::sync::mpsc::channel.
extern crate c_ares;
extern crate nix;

use self::nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollEventKind,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Condvar,
    Mutex,
    mpsc,
};
use std::thread;

struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    keep_going: Arc<(Mutex<bool>, Condvar)>,
    fd_handle: Option<thread::JoinHandle<()>>,
}

// A thread that keeps going processing file descriptors for c-ares, until it
// is asked to stop.
fn fd_handling_thread(
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    keep_going: Arc<(Mutex<bool>, Condvar)>) {
    let (ref lock, ref cvar) = *keep_going;
    let mut carry_on = lock.lock().unwrap();
    while *carry_on {
        process_ares_fds(ares_channel.clone());
        carry_on = cvar.wait(carry_on).unwrap();
    }
}

// Process file descriptors for c-ares, while it wants us to do so.
fn process_ares_fds(ares_channel: Arc<Mutex<c_ares::Channel>>) {
    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<c_ares::Socket>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        let sockets = ares_channel.lock().unwrap().get_sock();
        for (fd, readable, writable) in &sockets {
            let mut interest = EpollEventKind::empty();
            if readable { interest = interest | EPOLLIN; }
            if writable { interest = interest | EPOLLOUT; }
            let event = EpollEvent {
                events: interest,
                data: fd as u64,
            };
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &event).expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent {
            events: EpollEventKind::empty(),
            data: 0,
        };
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.lock().unwrap().process_fd(
                    c_ares::SOCKET_BAD,
                    c_ares::SOCKET_BAD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares.
                for event in &events[0..n] {
                    let active_fd = event.data as c_ares::Socket;
                    let rfd = if (event.events & EPOLLIN).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    let wfd = if (event.events & EPOLLOUT).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    ares_channel.lock().unwrap().process_fd(rfd, wfd);
                }
            }
        }
    }
}

impl Resolver {
    // Create a new Resolver
    pub fn new() -> Resolver {
        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_flags(c_ares::flags::STAYOPEN)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::with_options(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create a thread to handle file descriptors.
        let keep_going = Arc::new((Mutex::new(true), Condvar::new()));
        let channel_clone = locked_channel.clone();
        let keep_going_clone = keep_going.clone();
        let fd_handle = thread::spawn(move || {
            fd_handling_thread(channel_clone, keep_going_clone)
        });

        Resolver {
            ares_channel: locked_channel,
            keep_going: keep_going,
            fd_handle: Some(fd_handle),
        }
    }

    fn wake_fd_thread(&self) {
        let (ref _lock, ref cvar) = *self.keep_going;
        cvar.notify_one();
    }

    // A blocking NS query.  Achieve this by having the callback send the
    // result to a std::sync::mpsc::channel, and waiting on that channel.
    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ns(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking PTR query.
    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ptr(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking TXT query.
    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_txt(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Kick the file descriptor thread to stop.
        let (ref lock, ref cvar) = *self.keep_going;
        {
            let mut carry_on = lock.lock().unwrap();
            *carry_on = false;
        }
        cvar.notify_one();

        // Wait for it to do so.
        if let Some(handle) = self.fd_handle.take() {
            handle.join().unwrap();
        }
    }
}

fn print_ns_results(result: c_ares::Result<c_ares::NSResults>) {
    match result {
        Err(e) => {
            println!("NS lookup failed with error '{}'", e.description());
        }
        Ok(ns_results) => {
            println!("Successful NS lookup...");
            for ns_result in ns_results.aliases() {
                println!("{}", ns_result);
            }
        }
    }
}

fn print_ptr_results(result: c_ares::Result<c_ares::PTRResults>) {
    match result {
        Err(e) => {
            println!("PTR lookup failed with error '{}'", e.description());
        }
        Ok(ptr_results) => {
            println!("Successful PTR lookup...");
            for ptr_result in ptr_results.aliases() {
                println!("{}", ptr_result);
            }
        }
    }
}

fn print_txt_results(result: c_ares::Result<c_ares::TXTResults>) {
    match result {
        Err(e) => {
            println!("TXT lookup failed with error '{}'", e.description());
        }
        Ok(txt_results) => {
            println!("Successful TXT lookup...");
            for txt_result in &txt_results {
                println!(
                    "record start: {}, text: {}",
                    txt_result.record_start(),
                    txt_result.text());
            }
        }
    }
}

pub fn main() {
    // Create a Resolver.  Then make some requests.
    let resolver = Resolver::new();
    let result = resolver.query_ns("google.com");
    println!("");
    print_ns_results(result);

    let result = resolver.query_ptr("14.210.58.216.in-addr.arpa");
    println!("");
    print_ptr_results(result);

    let result = resolver.query_txt("google.com");
    println!("");
    print_txt_results(result);
}
<commit_msg>Quieten clippy<commit_after>// A variation on cares-epoll.rs
//
// Here we hide the use of epoll() behind a `Resolver` object.  We also
// transform the asynchronous c-ares interface into a synchronous one, by
// using a std::sync::mpsc::channel.
extern crate c_ares;
extern crate nix;

use self::nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollEventKind,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Condvar,
    Mutex,
    mpsc,
};
use std::thread;

struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    keep_going: Arc<(Mutex<bool>, Condvar)>,
    fd_handle: Option<thread::JoinHandle<()>>,
}

// A thread that keeps going processing file descriptors for c-ares, until it
// is asked to stop.
fn fd_handling_thread(
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    keep_going: Arc<(Mutex<bool>, Condvar)>) {
    let (ref lock, ref cvar) = *keep_going;
    let mut carry_on = lock.lock().unwrap();
    while *carry_on {
        process_ares_fds(ares_channel.clone());
        carry_on = cvar.wait(carry_on).unwrap();
    }
}

// Process file descriptors for c-ares, while it wants us to do so.
fn process_ares_fds(ares_channel: Arc<Mutex<c_ares::Channel>>) {
    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<c_ares::Socket>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        let sockets = ares_channel.lock().unwrap().get_sock();
        for (fd, readable, writable) in &sockets {
            let mut interest = EpollEventKind::empty();
            if readable { interest = interest | EPOLLIN; }
            if writable { interest = interest | EPOLLOUT; }
            let event = EpollEvent {
                events: interest,
                data: fd as u64,
            };
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &event).expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent {
            events: EpollEventKind::empty(),
            data: 0,
        };
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.lock().unwrap().process_fd(
                    c_ares::SOCKET_BAD,
                    c_ares::SOCKET_BAD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares.
                for event in &events[0..n] {
                    let active_fd = event.data as c_ares::Socket;
                    let rfd = if (event.events & EPOLLIN).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    let wfd = if (event.events & EPOLLOUT).is_empty() {
                        c_ares::SOCKET_BAD
                    } else {
                        active_fd
                    };
                    ares_channel.lock().unwrap().process_fd(rfd, wfd);
                }
            }
        }
    }
}

impl Resolver {
    // Create a new Resolver
    pub fn new() -> Resolver {
        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_flags(c_ares::flags::STAYOPEN)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::with_options(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create a thread to handle file descriptors.
        #[allow(mutex_atomic)]
        let keep_going = Arc::new((Mutex::new(true), Condvar::new()));
        let channel_clone = locked_channel.clone();
        let keep_going_clone = keep_going.clone();
        let fd_handle = thread::spawn(move || {
            fd_handling_thread(channel_clone, keep_going_clone)
        });

        Resolver {
            ares_channel: locked_channel,
            keep_going: keep_going,
            fd_handle: Some(fd_handle),
        }
    }

    fn wake_fd_thread(&self) {
        let (ref _lock, ref cvar) = *self.keep_going;
        cvar.notify_one();
    }

    // A blocking NS query.  Achieve this by having the callback send the
    // result to a std::sync::mpsc::channel, and waiting on that channel.
    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ns(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking PTR query.
    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_ptr(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }

    // A blocking TXT query.
    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        let (tx, rx) = mpsc::channel();
        self.ares_channel.lock().unwrap().query_txt(name, move |result| {
            tx.send(result).unwrap();
        });
        self.wake_fd_thread();
        rx.recv().unwrap()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Kick the file descriptor thread to stop.
        let (ref lock, ref cvar) = *self.keep_going;
        {
            let mut carry_on = lock.lock().unwrap();
            *carry_on = false;
        }
        cvar.notify_one();

        // Wait for it to do so.
        if let Some(handle) = self.fd_handle.take() {
            handle.join().unwrap();
        }
    }
}

fn print_ns_results(result: c_ares::Result<c_ares::NSResults>) {
    match result {
        Err(e) => {
            println!("NS lookup failed with error '{}'", e.description());
        }
        Ok(ns_results) => {
            println!("Successful NS lookup...");
            for ns_result in ns_results.aliases() {
                println!("{}", ns_result);
            }
        }
    }
}

fn print_ptr_results(result: c_ares::Result<c_ares::PTRResults>) {
    match result {
        Err(e) => {
            println!("PTR lookup failed with error '{}'", e.description());
        }
        Ok(ptr_results) => {
            println!("Successful PTR lookup...");
            for ptr_result in ptr_results.aliases() {
                println!("{}", ptr_result);
            }
        }
    }
}

fn print_txt_results(result: c_ares::Result<c_ares::TXTResults>) {
    match result {
        Err(e) => {
            println!("TXT lookup failed with error '{}'", e.description());
        }
        Ok(txt_results) => {
            println!("Successful TXT lookup...");
            for txt_result in &txt_results {
                println!(
                    "record start: {}, text: {}",
                    txt_result.record_start(),
                    txt_result.text());
            }
        }
    }
}

pub fn main() {
    // Create a Resolver.  Then make some requests.
    let resolver = Resolver::new();
    let result = resolver.query_ns("google.com");
    println!("");
    print_ns_results(result);

    let result = resolver.query_ptr("14.210.58.216.in-addr.arpa");
    println!("");
    print_ptr_results(result);

    let result = resolver.query_txt("google.com");
    println!("");
    print_txt_results(result);
}
<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

pub const PACKAGE_HOME: &'static str = "/opt/bldr/pkgs";
pub const SERVICE_HOME: &'static str = "/opt/bldr/srvc";
pub const PACKAGE_CACHE: &'static str = "/opt/bldr/cache/pkgs";
pub const GPG_CACHE: &'static str = "/opt/bldr/cache/gpg";
pub const KEY_CACHE: &'static str = "/opt/bldr/cache/keys";
<commit_msg>Global search/replace of srvc -> svc<commit_after>// Copyright:: Copyright (c) 2015-2016 Chef Software, Inc.
//
// The terms of the Evaluation Agreement (Bldr) between Chef Software Inc. and the party accessing
// this file ("Licensee") apply to Licensee's use of the Software until such time that the Software
// is made available under an open source license such as the Apache 2.0 License.

pub const PACKAGE_HOME: &'static str = "/opt/bldr/pkgs";
pub const SERVICE_HOME: &'static str = "/opt/bldr/svc";
pub const PACKAGE_CACHE: &'static str = "/opt/bldr/cache/pkgs";
pub const GPG_CACHE: &'static str = "/opt/bldr/cache/gpg";
pub const KEY_CACHE: &'static str = "/opt/bldr/cache/keys";
<|endoftext|>


<commit_before>use std::{io, run, uint, os, path, libc ,str};
use std::rand;
use std::rand::Rng;

static LOW:int = 0;
static HIGH:int = 3;

fn load(filename: ~str) -> ~[~str] {
	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(filename));

	if read.is_ok() {
	let file = read.unwrap();
	return file.read_lines();
	}

	println(fmt!("Error in reading the file: %?", read.unwrap_err()));
	return ~[];
}

fn main() {
        let mut rng = rand::task_rng();
	let dictionary: ~[~str] = load(~"words.txt");
	let max_size: uint = dictionary.len();
        let n: uint = rng.gen_integer_range(0u, max_size);
	let mut word: ~str = dictionary[n];
	println(fmt!("%?", n));
	println(fmt!("%?",max_size));
	println(word);
	let mut guesses :~[char] = "".iter().collect();
        let line = io::stdin().read_line();
	let guess_char: char = line.char_at(0);
	println(fmt!("%? guessed: ", guess_char));
	let mut has_char: bool = word.contains_char(guess_char);
	println(fmt!("%?", has_char));
}
<commit_msg>guess letters<commit_after>use std::{io, path};
use std::rand;
use std::rand::Rng;

static LOW:int = 0;
static HIGH:int = 3;

fn load(filename: ~str) -> ~[~str] {
	let read: Result<@Reader, ~str>;
	read = io::file_reader(~path::Path(filename));

	if read.is_ok() {
	let file = read.unwrap();
	return file.read_lines();
	}

	println(fmt!("Error in reading the file: %?", read.unwrap_err()));
	return ~[];
}

fn main() {
        let mut rng = rand::task_rng();
	let dictionary: ~[~str] = load(~"words.txt");
	let max_size: uint = dictionary.len();
        let n: uint = rng.gen_integer_range(0u, max_size);
	let word: ~str = dictionary[n];
	let word_len: uint = word.char_len();

	let mut i = 0;
	while (i < word_len) {
        	print("_ ");
		i += 1;
        }
        println("");

	let mut j = 0;
        let max_guess : uint = 8;
	while (j < max_guess){

		let line = io::stdin().read_line();
		let guess_char: char = line.char_at(0);
		println(fmt!("%? guessed: ", guess_char));
		let has_char: bool = word.contains_char(guess_char);

		if (has_char){
       			let mut i = 0;
			while (i < word_len) {
				if(word.char_at(i) != guess_char){
        	 			print("_ ");
                		}else{
		 			print(fmt!("%c", guess_char));
		 			print(" ");
				}
				i += 1;
       			 }

		}
		else{
			j += 1;
		}
	}

}
<|endoftext|>


<commit_before>use super::super::rosxmlrpc::Response;
use super::clock::{Clock, Rate, RealClock, SimulatedClock};
use super::error::{ErrorKind, Result, ResultExt};
use super::master::{self, Master, Topic};
use super::naming::{self, Resolver};
use super::raii::{Publisher, Service, Subscriber};
use super::resolve;
use super::slave::Slave;
use msg::rosgraph_msgs::{Clock as ClockMsg, Log};
use msg::std_msgs::Header;
use serde::{Deserialize, Serialize};
use std::sync::{mpsc, Arc};
use std::time;
use tcpros::{Client, Message, ServicePair, ServiceResult};
use time::{Duration, Time};
use xml_rpc;
use yaml_rust::{Yaml, YamlLoader};

pub struct Ros {
    master: Arc<Master>,
    slave: Arc<Slave>,
    hostname: String,
    resolver: Resolver,
    name: String,
    clock: Arc<Clock>,
    static_subs: Vec<Subscriber>,
    logger: Option<Publisher<Log>>,
    shutdown_tx: mpsc::Sender<()>,
    shutdown_rx: Option<mpsc::Receiver<()>>,
}

impl Ros {
    pub fn new(name: &str) -> Result<Ros> {
        let mut namespace = resolve::namespace();
        if !namespace.starts_with('/') {
            namespace = format!("/{}", namespace);
        }
        let master_uri = resolve::master();
        let hostname = resolve::hostname();
        let name = resolve::name(name);
        let mut ros = Ros::new_raw(&master_uri, &hostname, &namespace, &name)?;
        for (src, dest) in resolve::mappings() {
            ros.map(&src, &dest)?;
        }
        for (src, dest) in resolve::params() {
            let data = YamlLoader::load_from_str(&dest)
                .chain_err(|| format!("Failed to load YAML: {}", dest))?
                .into_iter()
                .next()
                .ok_or_else(|| format!("Failed to load YAML: {}", dest))?;
            let param = ros
                .param(&src)
                .ok_or_else(|| format!("Failed to resolve name: {}", src))?;
            param.set_raw(yaml_to_xmlrpc(data)?)?;
        }

        if ros
            .param("/use_sim_time")
            .and_then(|v| v.get().ok())
            .unwrap_or(false)
        {
            let clock = Arc::new(SimulatedClock::default());
            let ros_clock = Arc::clone(&clock);
            let sub = ros
                .subscribe::<ClockMsg, _>("/clock", move |v| clock.trigger(v.clock))
                .chain_err(|| "Failed to subscribe to simulated clock")?;
            ros.static_subs.push(sub);
            ros.clock = ros_clock;
        }

        ros.logger = Some(ros.publish("/rosout")?);

        Ok(ros)
    }

    fn new_raw(master_uri: &str, hostname: &str, namespace: &str, name: &str) -> Result<Ros> {
        let namespace = namespace.trim_start_matches('/');

        if name.contains('/') {
            bail!(ErrorKind::Naming(
                naming::error::ErrorKind::IllegalCharacter(name.into()),
            ));
        }

        let name = format!("{}/{}", namespace, name);
        let resolver = Resolver::new(&name)?;

        let (shutdown_tx, shutdown_rx) = mpsc::channel();

        let slave = Slave::new(master_uri, hostname, 0, &name, shutdown_tx.clone())?;
        let master = Master::new(master_uri, &name, slave.uri());

        Ok(Ros {
            master: Arc::new(master),
            slave: Arc::new(slave),
            hostname: String::from(hostname),
            resolver,
            name,
            clock: Arc::new(RealClock::default()),
            static_subs: Vec::new(),
            logger: None,
            shutdown_tx,
            shutdown_rx: Some(shutdown_rx),
        })
    }

    fn map(&mut self, source: &str, destination: &str) -> Result<()> {
        self.resolver.map(source, destination).map_err(|v| v.into())
    }

    #[inline]
    pub fn uri(&self) -> &str {
        self.slave.uri()
    }

    #[inline]
    pub fn name(&self) -> &str {
        &self.name
    }

    #[inline]
    pub fn hostname(&self) -> &str {
        &self.hostname
    }

    #[inline]
    pub fn now(&self) -> Time {
        self.clock.now()
    }

    #[inline]
    pub fn sleep(&self, d: Duration) {
        self.clock.await_init();
        self.clock.sleep(d);
    }

    #[inline]
    pub fn shutdown_sender(&self) -> mpsc::Sender<()> {
        self.shutdown_tx.clone()
    }

    pub fn rate(&self, rate: f64) -> Rate {
        self.clock.await_init();
        let nanos = 1_000_000_000.0 / rate;
        Rate::new(Arc::clone(&self.clock), Duration::from_nanos(nanos as i64))
    }

    #[inline]
    pub fn is_ok(&self) -> bool {
        if let Some(ref rx) = self.shutdown_rx {
            rx.try_recv() == Err(mpsc::TryRecvError::Empty)
        } else {
            return false;
        }
    }

    #[inline]
    pub fn spin(&mut self) -> Spinner {
        Spinner {
            shutdown_rx: self.shutdown_rx.take(),
        }
    }

    pub fn param(&self, name: &str) -> Option<Parameter> {
        self.resolver.translate(name).ok().map(|v| Parameter {
            master: Arc::clone(&self.master),
            name: v,
        })
    }

    pub fn parameters(&self) -> Response<Vec<String>> {
        self.master.get_param_names()
    }

    pub fn state(&self) -> Response<master::SystemState> {
        self.master.get_system_state().map(Into::into)
    }

    pub fn topics(&self) -> Response<Vec<Topic>> {
        self.master
            .get_topic_types()
            .map(|v| v.into_iter().map(Into::into).collect())
    }

    pub fn client<T: ServicePair>(&self, service: &str) -> Result<Client<T>> {
        let name = self.resolver.translate(service)?;
        let uri = self.master.lookup_service(&name)?;
        Ok(Client::new(&self.name, &uri, &name))
    }

    pub fn wait_for_service(&self, service: &str, timeout: Option<time::Duration>) -> Result<()> {
        use rosxmlrpc::ResponseError;
        use std::thread::sleep;

        let name = self.resolver.translate(service)?;
        let now = ::std::time::Instant::now();
        loop {
            let e = match self.master.lookup_service(&name) {
                Ok(_) => return Ok(()),
                Err(e) => e,
            };
            match e {
                ResponseError::Client(ref m) if m == "no provider" => {
                    if let Some(ref timeout) = timeout {
                        if now.elapsed() > *timeout {
                            return Err(ErrorKind::TimeoutError.into());
                        }
                    }
                    sleep(time::Duration::from_millis(100));
                    continue;
                }
                _ => {}
            }
            return Err(e.into());
        }
    }

    pub fn service<T, F>(&mut self, service: &str, handler: F) -> Result<Service>
    where
        T: ServicePair,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let name = self.resolver.translate(service)?;
        Service::new::<T, F>(
            Arc::clone(&self.master),
            Arc::clone(&self.slave),
            &self.hostname,
            &name,
            handler,
        )
    }

    pub fn subscribe<T, F>(&mut self, topic: &str, callback: F) -> Result<Subscriber>
    where
        T: Message,
        F: Fn(T) -> () + Send + 'static,
    {
        let name = self.resolver.translate(topic)?;
        Subscriber::new::<T, F>(
            Arc::clone(&self.master),
            Arc::clone(&self.slave),
            &name,
            callback,
        )
    }

    pub fn publish<T>(&mut self, topic: &str) -> Result<Publisher<T>>
    where
        T: Message,
    {
        let name = self.resolver.translate(topic)?;
        Publisher::new(
            Arc::clone(&self.master),
            Arc::clone(&self.slave),
            Arc::clone(&self.clock),
            &self.hostname,
            &name,
        )
    }

    pub fn log(&mut self, level: i8, msg: String, file: &str, line: u32) {
        let logger = &mut match self.logger {
            Some(ref mut v) => v,
            None => return,
        };
        let topics = self.slave.publications.get_topic_names();
        let message = Log {
            header: Header::default(),
            level,
            msg,
            name: self.name.clone(),
            line,
            file: file.into(),
            function: String::default(),
            topics,
        };
        if let Err(err) = logger.send(message) {
            error!("Logging error: {}", err);
        }
    }
}

pub struct Parameter {
    master: Arc<Master>,
    name: String,
}

impl Parameter {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn get<'b, T: Deserialize<'b>>(&self) -> Response<T> {
        self.master.get_param::<T>(&self.name)
    }

    pub fn get_raw(&self) -> Response<xml_rpc::Value> {
        self.master.get_param_any(&self.name)
    }

    pub fn set<T: Serialize>(&self, value: &T) -> Response<()> {
        self.master.set_param::<T>(&self.name, value).and(Ok(()))
    }

    pub fn set_raw(&self, value: xml_rpc::Value) -> Response<()> {
        self.master.set_param_any(&self.name, value).and(Ok(()))
    }

    pub fn delete(&self) -> Response<()> {
        self.master.delete_param(&self.name).and(Ok(()))
    }

    pub fn exists(&self) -> Response<bool> {
        self.master.has_param(&self.name)
    }

    pub fn search(&self) -> Response<String> {
        self.master.search_param(&self.name)
    }
}

fn yaml_to_xmlrpc(val: Yaml) -> Result<xml_rpc::Value> {
    Ok(match val {
        Yaml::Real(v) => xml_rpc::Value::Double(v.parse().chain_err(|| "Failed to parse float")?),
        Yaml::Integer(v) => xml_rpc::Value::Int(v as i32),
        Yaml::String(v) => xml_rpc::Value::String(v),
        Yaml::Boolean(v) => xml_rpc::Value::Bool(v),
        Yaml::Array(v) => {
            xml_rpc::Value::Array(v.into_iter().map(yaml_to_xmlrpc).collect::<Result<_>>()?)
        }
        Yaml::Hash(v) => xml_rpc::Value::Struct(
            v.into_iter()
                .map(|(k, v)| Ok((yaml_to_string(k)?, yaml_to_xmlrpc(v)?)))
                .collect::<Result<_>>()?,
        ),
        Yaml::Alias(_) => bail!("Alias is not supported"),
        Yaml::Null => bail!("Illegal null value"),
        Yaml::BadValue => bail!("Bad value provided"),
    })
}

fn yaml_to_string(val: Yaml) -> Result<String> {
    Ok(match val {
        Yaml::Real(v) | Yaml::String(v) => v,
        Yaml::Integer(v) => v.to_string(),
        Yaml::Boolean(true) => "true".into(),
        Yaml::Boolean(false) => "false".into(),
        _ => bail!("Hash keys need to be strings"),
    })
}

pub struct Spinner {
    shutdown_rx: Option<mpsc::Receiver<()>>,
}

impl Drop for Spinner {
    fn drop(&mut self) {
        if let Some(ref rx) = self.shutdown_rx {
            rx.recv().is_ok();
        }
    }
}
<commit_msg>Fix mistaken deprecation fix.<commit_after>use super::super::rosxmlrpc::Response;
use super::clock::{Clock, Rate, RealClock, SimulatedClock};
use super::error::{ErrorKind, Result, ResultExt};
use super::master::{self, Master, Topic};
use super::naming::{self, Resolver};
use super::raii::{Publisher, Service, Subscriber};
use super::resolve;
use super::slave::Slave;
use msg::rosgraph_msgs::{Clock as ClockMsg, Log};
use msg::std_msgs::Header;
use serde::{Deserialize, Serialize};
use std::sync::{mpsc, Arc};
use std::time;
use tcpros::{Client, Message, ServicePair, ServiceResult};
use time::{Duration, Time};
use xml_rpc;
use yaml_rust::{Yaml, YamlLoader};

pub struct Ros {
    master: Arc<Master>,
    slave: Arc<Slave>,
    hostname: String,
    resolver: Resolver,
    name: String,
    clock: Arc<Clock>,
    static_subs: Vec<Subscriber>,
    logger: Option<Publisher<Log>>,
    shutdown_tx: mpsc::Sender<()>,
    shutdown_rx: Option<mpsc::Receiver<()>>,
}

impl Ros {
    pub fn new(name: &str) -> Result<Ros> {
        let mut namespace = resolve::namespace();
        if !namespace.starts_with('/') {
            namespace = format!("/{}", namespace);
        }
        let master_uri = resolve::master();
        let hostname = resolve::hostname();
        let name = resolve::name(name);
        let mut ros = Ros::new_raw(&master_uri, &hostname, &namespace, &name)?;
        for (src, dest) in resolve::mappings() {
            ros.map(&src, &dest)?;
        }
        for (src, dest) in resolve::params() {
            let data = YamlLoader::load_from_str(&dest)
                .chain_err(|| format!("Failed to load YAML: {}", dest))?
                .into_iter()
                .next()
                .ok_or_else(|| format!("Failed to load YAML: {}", dest))?;
            let param = ros
                .param(&src)
                .ok_or_else(|| format!("Failed to resolve name: {}", src))?;
            param.set_raw(yaml_to_xmlrpc(data)?)?;
        }

        if ros
            .param("/use_sim_time")
            .and_then(|v| v.get().ok())
            .unwrap_or(false)
        {
            let clock = Arc::new(SimulatedClock::default());
            let ros_clock = Arc::clone(&clock);
            let sub = ros
                .subscribe::<ClockMsg, _>("/clock", move |v| clock.trigger(v.clock))
                .chain_err(|| "Failed to subscribe to simulated clock")?;
            ros.static_subs.push(sub);
            ros.clock = ros_clock;
        }

        ros.logger = Some(ros.publish("/rosout")?);

        Ok(ros)
    }

    fn new_raw(master_uri: &str, hostname: &str, namespace: &str, name: &str) -> Result<Ros> {
        let namespace = namespace.trim_end_matches('/');

        if name.contains('/') {
            bail!(ErrorKind::Naming(
                naming::error::ErrorKind::IllegalCharacter(name.into()),
            ));
        }

        let name = format!("{}/{}", namespace, name);
        let resolver = Resolver::new(&name)?;

        let (shutdown_tx, shutdown_rx) = mpsc::channel();

        let slave = Slave::new(master_uri, hostname, 0, &name, shutdown_tx.clone())?;
        let master = Master::new(master_uri, &name, slave.uri());

        Ok(Ros {
            master: Arc::new(master),
            slave: Arc::new(slave),
            hostname: String::from(hostname),
            resolver,
            name,
            clock: Arc::new(RealClock::default()),
            static_subs: Vec::new(),
            logger: None,
            shutdown_tx,
            shutdown_rx: Some(shutdown_rx),
        })
    }

    fn map(&mut self, source: &str, destination: &str) -> Result<()> {
        self.resolver.map(source, destination).map_err(|v| v.into())
    }

    #[inline]
    pub fn uri(&self) -> &str {
        self.slave.uri()
    }

    #[inline]
    pub fn name(&self) -> &str {
        &self.name
    }

    #[inline]
    pub fn hostname(&self) -> &str {
        &self.hostname
    }

    #[inline]
    pub fn now(&self) -> Time {
        self.clock.now()
    }

    #[inline]
    pub fn sleep(&self, d: Duration) {
        self.clock.await_init();
        self.clock.sleep(d);
    }

    #[inline]
    pub fn shutdown_sender(&self) -> mpsc::Sender<()> {
        self.shutdown_tx.clone()
    }

    pub fn rate(&self, rate: f64) -> Rate {
        self.clock.await_init();
        let nanos = 1_000_000_000.0 / rate;
        Rate::new(Arc::clone(&self.clock), Duration::from_nanos(nanos as i64))
    }

    #[inline]
    pub fn is_ok(&self) -> bool {
        if let Some(ref rx) = self.shutdown_rx {
            rx.try_recv() == Err(mpsc::TryRecvError::Empty)
        } else {
            return false;
        }
    }

    #[inline]
    pub fn spin(&mut self) -> Spinner {
        Spinner {
            shutdown_rx: self.shutdown_rx.take(),
        }
    }

    pub fn param(&self, name: &str) -> Option<Parameter> {
        self.resolver.translate(name).ok().map(|v| Parameter {
            master: Arc::clone(&self.master),
            name: v,
        })
    }

    pub fn parameters(&self) -> Response<Vec<String>> {
        self.master.get_param_names()
    }

    pub fn state(&self) -> Response<master::SystemState> {
        self.master.get_system_state().map(Into::into)
    }

    pub fn topics(&self) -> Response<Vec<Topic>> {
        self.master
            .get_topic_types()
            .map(|v| v.into_iter().map(Into::into).collect())
    }

    pub fn client<T: ServicePair>(&self, service: &str) -> Result<Client<T>> {
        let name = self.resolver.translate(service)?;
        let uri = self.master.lookup_service(&name)?;
        Ok(Client::new(&self.name, &uri, &name))
    }

    pub fn wait_for_service(&self, service: &str, timeout: Option<time::Duration>) -> Result<()> {
        use rosxmlrpc::ResponseError;
        use std::thread::sleep;

        let name = self.resolver.translate(service)?;
        let now = ::std::time::Instant::now();
        loop {
            let e = match self.master.lookup_service(&name) {
                Ok(_) => return Ok(()),
                Err(e) => e,
            };
            match e {
                ResponseError::Client(ref m) if m == "no provider" => {
                    if let Some(ref timeout) = timeout {
                        if now.elapsed() > *timeout {
                            return Err(ErrorKind::TimeoutError.into());
                        }
                    }
                    sleep(time::Duration::from_millis(100));
                    continue;
                }
                _ => {}
            }
            return Err(e.into());
        }
    }

    pub fn service<T, F>(&mut self, service: &str, handler: F) -> Result<Service>
    where
        T: ServicePair,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let name = self.resolver.translate(service)?;
        Service::new::<T, F>(
            Arc::clone(&self.master),
            Arc::clone(&self.slave),
            &self.hostname,
            &name,
            handler,
        )
    }

    pub fn subscribe<T, F>(&mut self, topic: &str, callback: F) -> Result<Subscriber>
    where
        T: Message,
        F: Fn(T) -> () + Send + 'static,
    {
        let name = self.resolver.translate(topic)?;
        Subscriber::new::<T, F>(
            Arc::clone(&self.master),
            Arc::clone(&self.slave),
            &name,
            callback,
        )
    }

    pub fn publish<T>(&mut self, topic: &str) -> Result<Publisher<T>>
    where
        T: Message,
    {
        let name = self.resolver.translate(topic)?;
        Publisher::new(
            Arc::clone(&self.master),
            Arc::clone(&self.slave),
            Arc::clone(&self.clock),
            &self.hostname,
            &name,
        )
    }

    pub fn log(&mut self, level: i8, msg: String, file: &str, line: u32) {
        let logger = &mut match self.logger {
            Some(ref mut v) => v,
            None => return,
        };
        let topics = self.slave.publications.get_topic_names();
        let message = Log {
            header: Header::default(),
            level,
            msg,
            name: self.name.clone(),
            line,
            file: file.into(),
            function: String::default(),
            topics,
        };
        if let Err(err) = logger.send(message) {
            error!("Logging error: {}", err);
        }
    }
}

pub struct Parameter {
    master: Arc<Master>,
    name: String,
}

impl Parameter {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn get<'b, T: Deserialize<'b>>(&self) -> Response<T> {
        self.master.get_param::<T>(&self.name)
    }

    pub fn get_raw(&self) -> Response<xml_rpc::Value> {
        self.master.get_param_any(&self.name)
    }

    pub fn set<T: Serialize>(&self, value: &T) -> Response<()> {
        self.master.set_param::<T>(&self.name, value).and(Ok(()))
    }

    pub fn set_raw(&self, value: xml_rpc::Value) -> Response<()> {
        self.master.set_param_any(&self.name, value).and(Ok(()))
    }

    pub fn delete(&self) -> Response<()> {
        self.master.delete_param(&self.name).and(Ok(()))
    }

    pub fn exists(&self) -> Response<bool> {
        self.master.has_param(&self.name)
    }

    pub fn search(&self) -> Response<String> {
        self.master.search_param(&self.name)
    }
}

fn yaml_to_xmlrpc(val: Yaml) -> Result<xml_rpc::Value> {
    Ok(match val {
        Yaml::Real(v) => xml_rpc::Value::Double(v.parse().chain_err(|| "Failed to parse float")?),
        Yaml::Integer(v) => xml_rpc::Value::Int(v as i32),
        Yaml::String(v) => xml_rpc::Value::String(v),
        Yaml::Boolean(v) => xml_rpc::Value::Bool(v),
        Yaml::Array(v) => {
            xml_rpc::Value::Array(v.into_iter().map(yaml_to_xmlrpc).collect::<Result<_>>()?)
        }
        Yaml::Hash(v) => xml_rpc::Value::Struct(
            v.into_iter()
                .map(|(k, v)| Ok((yaml_to_string(k)?, yaml_to_xmlrpc(v)?)))
                .collect::<Result<_>>()?,
        ),
        Yaml::Alias(_) => bail!("Alias is not supported"),
        Yaml::Null => bail!("Illegal null value"),
        Yaml::BadValue => bail!("Bad value provided"),
    })
}

fn yaml_to_string(val: Yaml) -> Result<String> {
    Ok(match val {
        Yaml::Real(v) | Yaml::String(v) => v,
        Yaml::Integer(v) => v.to_string(),
        Yaml::Boolean(true) => "true".into(),
        Yaml::Boolean(false) => "false".into(),
        _ => bail!("Hash keys need to be strings"),
    })
}

pub struct Spinner {
    shutdown_rx: Option<mpsc::Receiver<()>>,
}

impl Drop for Spinner {
    fn drop(&mut self) {
        if let Some(ref rx) = self.shutdown_rx {
            rx.recv().is_ok();
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use darling::util::Override;
use derive_common::cg;
use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt};
use syn::{self, Data, Path, WhereClause};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(mut input: syn::DeriveInput) -> TokenStream {
    let mut where_clause = input.generics.where_clause.take();
    for param in input.generics.type_params() {
        cg::add_predicate(&mut where_clause, parse_quote!(#param: style_traits::ToCss));
    }

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(
            input_attrs.function.is_none(),
            "#[css(function)] is not allowed on enums"
        );
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }

    let match_body = {
        let s = Structure::new(&input);
        s.each_variant(|variant| derive_variant_arm(variant, &mut where_clause))
    };
    input.generics.where_clause = where_clause;

    let name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let mut impls = quote! {
        impl #impl_generics style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut style_traits::CssWriter<W>,
            ) -> std::fmt::Result
            where
                W: std::fmt::Write,
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                    style_traits::ToCss::to_css(
                        self,
                        &mut style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(variant: &VariantInfo, generics: &mut Option<WhereClause>) -> TokenStream {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(&variant.ast().ident.to_string());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.skip {
        return quote!(Ok(()));
    }
    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        quote! {
            std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, generics, separator)
    } else {
        quote! {
            std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut Option<WhereClause>,
    separator: &str,
) -> TokenStream {
    let mut iter = bindings
        .iter()
        .filter_map(|binding| {
            let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
            if attrs.skip {
                return None;
            }
            Some((binding, attrs))
        })
        .peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if attrs.field_bound {
            let ty = &first.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: style_traits::ToCss));
        }
        let mut expr = quote! { style_traits::ToCss::to_css(#first, dest) };
        if let Some(condition) = attrs.skip_if {
            expr = quote! {
                if !#condition(#first) {
                    #expr
                }
            }
        }

        if let Some(condition) = attrs.contextual_skip_if {
            expr = quote! {
                if !#condition(#(#bindings), *) {
                    #expr
                }
            }
        }
        return expr;
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause, bindings);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause, bindings).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut Option<WhereClause>,
    bindings: &[BindingInfo],
) -> TokenStream {
    let mut expr = if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.raw_item(#if_empty)?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else if attrs.represents_keyword {
        let ident = field
            .ast()
            .ident
            .as_ref()
            .expect("Unnamed field with represents_keyword?");
        let ident = cg::to_css_identifier(&ident.to_string());
        quote! {
            if *#field {
                writer.raw_item(#ident)?;
            }
        }
    } else {
        if attrs.field_bound {
            let ty = &field.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: style_traits::ToCss));
        }
        quote! { writer.item(#field)?; }
    };

    if let Some(condition) = attrs.skip_if {
        expr = quote! {
            if !#condition(#field) {
                #expr
            }
        }
    }

    if let Some(condition) = attrs.contextual_skip_if {
        expr = quote! {
            if !#condition(#(#bindings), *) {
                #expr
            }
        }
    }

    expr
}

#[derive(Default, FromDeriveInput)]
#[darling(attributes(css), default)]
pub struct CssInputAttrs {
    pub derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    pub function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    pub comma: bool,
}

#[derive(Default, FromVariant)]
#[darling(attributes(css), default)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    pub derive_debug: bool,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub skip: bool,
}

#[derive(Default, FromField)]
#[darling(attributes(css), default)]
pub struct CssFieldAttrs {
    pub if_empty: Option<String>,
    pub field_bound: bool,
    pub iterable: bool,
    pub skip: bool,
    pub represents_keyword: bool,
    pub contextual_skip_if: Option<Path>,
    pub skip_if: Option<Path>,
}
<commit_msg>style: Fix clippy warnings<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use darling::util::Override;
use derive_common::cg;
use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt};
use syn::{self, Data, Path, WhereClause};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(mut input: syn::DeriveInput) -> TokenStream {
    let mut where_clause = input.generics.where_clause.take();
    for param in input.generics.type_params() {
        cg::add_predicate(&mut where_clause, parse_quote!(#param: style_traits::ToCss));
    }

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    if let Data::Enum(_) = input.data {
        assert!(
            input_attrs.function.is_none(),
            "#[css(function)] is not allowed on enums"
        );
        assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
    }

    let match_body = {
        let s = Structure::new(&input);
        s.each_variant(|variant| derive_variant_arm(variant, &mut where_clause))
    };
    input.generics.where_clause = where_clause;

    let name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let mut impls = quote! {
        impl #impl_generics style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut style_traits::CssWriter<W>,
            ) -> std::fmt::Result
            where
                W: std::fmt::Write,
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                    style_traits::ToCss::to_css(
                        self,
                        &mut style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(variant: &VariantInfo, generics: &mut Option<WhereClause>) -> TokenStream {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(&variant.ast().ident.to_string());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.skip {
        return quote!(Ok(()));
    }
    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        quote! {
            std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        derive_variant_fields_expr(bindings, generics, separator)
    } else {
        quote! {
            std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push('(');
        expr = quote! {
            std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

fn derive_variant_fields_expr(
    bindings: &[BindingInfo],
    where_clause: &mut Option<WhereClause>,
    separator: &str,
) -> TokenStream {
    let mut iter = bindings
        .iter()
        .filter_map(|binding| {
            let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
            if attrs.skip {
                return None;
            }
            Some((binding, attrs))
        })
        .peekable();

    let (first, attrs) = match iter.next() {
        Some(pair) => pair,
        None => return quote! { Ok(()) },
    };
    if !attrs.iterable && iter.peek().is_none() {
        if attrs.field_bound {
            let ty = &first.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: style_traits::ToCss));
        }
        let mut expr = quote! { style_traits::ToCss::to_css(#first, dest) };
        if let Some(condition) = attrs.skip_if {
            expr = quote! {
                if !#condition(#first) {
                    #expr
                }
            }
        }

        if let Some(condition) = attrs.contextual_skip_if {
            expr = quote! {
                if !#condition(#(#bindings), *) {
                    #expr
                }
            }
        }
        return expr;
    }

    let mut expr = derive_single_field_expr(first, attrs, where_clause, bindings);
    for (binding, attrs) in iter {
        derive_single_field_expr(binding, attrs, where_clause, bindings).to_tokens(&mut expr)
    }

    quote! {{
        let mut writer = style_traits::values::SequenceWriter::new(dest, #separator);
        #expr
        Ok(())
    }}
}

fn derive_single_field_expr(
    field: &BindingInfo,
    attrs: CssFieldAttrs,
    where_clause: &mut Option<WhereClause>,
    bindings: &[BindingInfo],
) -> TokenStream {
    let mut expr = if attrs.iterable {
        if let Some(if_empty) = attrs.if_empty {
            return quote! {
                {
                    let mut iter = #field.iter().peekable();
                    if iter.peek().is_none() {
                        writer.raw_item(#if_empty)?;
                    } else {
                        for item in iter {
                            writer.item(&item)?;
                        }
                    }
                }
            };
        }
        quote! {
            for item in #field.iter() {
                writer.item(&item)?;
            }
        }
    } else if attrs.represents_keyword {
        let ident = field
            .ast()
            .ident
            .as_ref()
            .expect("Unnamed field with represents_keyword?");
        let ident = cg::to_css_identifier(&ident.to_string());
        quote! {
            if *#field {
                writer.raw_item(#ident)?;
            }
        }
    } else {
        if attrs.field_bound {
            let ty = &field.ast().ty;
            cg::add_predicate(where_clause, parse_quote!(#ty: style_traits::ToCss));
        }
        quote! { writer.item(#field)?; }
    };

    if let Some(condition) = attrs.skip_if {
        expr = quote! {
            if !#condition(#field) {
                #expr
            }
        }
    }

    if let Some(condition) = attrs.contextual_skip_if {
        expr = quote! {
            if !#condition(#(#bindings), *) {
                #expr
            }
        }
    }

    expr
}

#[derive(Default, FromDeriveInput)]
#[darling(attributes(css), default)]
pub struct CssInputAttrs {
    pub derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    pub function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    pub comma: bool,
}

#[derive(Default, FromVariant)]
#[darling(attributes(css), default)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    pub derive_debug: bool,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub skip: bool,
}

#[derive(Default, FromField)]
#[darling(attributes(css), default)]
pub struct CssFieldAttrs {
    pub if_empty: Option<String>,
    pub field_bound: bool,
    pub iterable: bool,
    pub skip: bool,
    pub represents_keyword: bool,
    pub contextual_skip_if: Option<Path>,
    pub skip_if: Option<Path>,
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref CMD_RESOURCE_DIR: Arc<Mutex<Option<String>>> = {
        Arc::new(Mutex::new(None))
    };
}

pub fn set_resources_path(path: Option<String>) {
    let mut dir = CMD_RESOURCE_DIR.lock().unwrap();
    *dir = path;
}

#[cfg(target_os = "android")]
pub fn resources_dir_path() -> PathBuf {
    PathBuf::from("/sdcard/servo/")
}

#[cfg(not(target_os = "android"))]
pub fn resources_dir_path() -> PathBuf {
    use std::env;

    match *CMD_RESOURCE_DIR.lock().unwrap() {
        Some(ref path) => PathBuf::from(path),
        None => {
            // FIXME: Find a way to not rely on the executable being
            // under `<servo source>[/$target_triple]/target/debug`
            // or `<servo source>[/$target_triple]/target/release`.
            let mut path = env::current_exe().expect("can't get exe path");
            path.pop();
            path.push("resources");
            if !path.is_dir() {   // resources dir not in same dir as exe?
                // exe is probably in target/{debug,release} so we need to go back to topdir
                path.pop();
                path.pop();
                path.pop();
                path.push("resources");
                if !path.is_dir() {
                    // exe is probably in target/$target_triple/{debug,release} so go back one more
                    path.pop();
                    path.pop();
                    path.push("resources");
                }
            }
            path
        }
    }
}

pub fn read_resource_file(relative_path_components: &[&str]) -> io::Result<Vec<u8>> {
    let mut path = resources_dir_path();
    for component in relative_path_components {
        path.push(component);
    }
    let mut file = try!(File::open(&path));
    let mut data = Vec::new();
    try!(file.read_to_end(&mut data));
    Ok(data)
}
<commit_msg>Follow executable symlink to resolve resources directory<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref CMD_RESOURCE_DIR: Arc<Mutex<Option<String>>> = {
        Arc::new(Mutex::new(None))
    };
}

pub fn set_resources_path(path: Option<String>) {
    let mut dir = CMD_RESOURCE_DIR.lock().unwrap();
    *dir = path;
}

#[cfg(target_os = "android")]
pub fn resources_dir_path() -> PathBuf {
    PathBuf::from("/sdcard/servo/")
}

#[cfg(not(target_os = "android"))]
pub fn resources_dir_path() -> PathBuf {
    use std::env;

    match *CMD_RESOURCE_DIR.lock().unwrap() {
        Some(ref path) => PathBuf::from(path),
        None => {
            // FIXME: Find a way to not rely on the executable being
            // under `<servo source>[/$target_triple]/target/debug`
            // or `<servo source>[/$target_triple]/target/release`.
            let mut path = env::current_exe().expect("can't get exe path");
            // Follow symlink
            path = path.canonicalize().expect("path does not exist");
            path.pop();
            path.push("resources");
            if !path.is_dir() {   // resources dir not in same dir as exe?
                // exe is probably in target/{debug,release} so we need to go back to topdir
                path.pop();
                path.pop();
                path.pop();
                path.push("resources");
                if !path.is_dir() {
                    // exe is probably in target/$target_triple/{debug,release} so go back one more
                    path.pop();
                    path.pop();
                    path.push("resources");
                }
            }
            path
        }
    }
}

pub fn read_resource_file(relative_path_components: &[&str]) -> io::Result<Vec<u8>> {
    let mut path = resources_dir_path();
    for component in relative_path_components {
        path.push(component);
    }
    let mut file = try!(File::open(&path));
    let mut data = Vec::new();
    try!(file.read_to_end(&mut data));
    Ok(data)
}
<|endoftext|>


<commit_before>// main defines the program entry point
fn main() {
	// println!() is a macro which functions similar to C printf()
	println!("hello, {}!\n", "world");

	let item = "apple";
	let price: f32 =
		if item == "apple" {
			1.00
		} else if item == "banana" {
			1.50
		} else {
			2.00
		};

	println!("The price of {} is {}", item, price);
}
<commit_msg>rust: function calls and basic match statements<commit_after>// main defines the program entry point
fn main() {
	// println!() is a macro which functions similar to C printf()
	println!("hello, {}!\n", "world");

	// All variables are immutable unless declared with "let mut"
	let item = "apple";

	// Declaring price using conditional statements
	let price: f32 =
		if item == "apple" {
			1.00
		} else if item == "banana" {
			1.50
		} else {
			2.00
		};

	println!("The price of {} is {}", item, price);

	// Calling and using function return
	println!("signum({}) = {}\n", -10i, signum(-10));

	// The "match" statement is a more generalized version of C "switch", which accepts expressions
	let num = 1i;
	match num {
		// Single condition
		0     => { println!("zero") }
		// One or the other
		1 | 2 => { println!("one or two") }
		// Range of conditions
		3..10 => { println!("three to ten") }
		// match is exhaustive, so a wildcard case is required at compile-time
		_     => { println!("something else") }
	}
}

// signum returns the sign of an integer
fn signum(x: int) -> int {
	if x < 0 { -1 }
	else if x > 0 { 1 }
	else { 0 }
}
<|endoftext|>


<commit_before>//! Module for the data set reader
use crate::dataset::*;
use crate::error::{Error, Result};
use dicom_core::{DataElementHeader, Length, VR};
use dicom_encoding::encode::{Encode, EncodeTo};
use dicom_encoding::text::{SpecificCharacterSet, TextCodec};
use dicom_encoding::TransferSyntax;
use std::io::Write;

/// A writer-specific token representing a sequence or item start.
#[derive(Debug)]
struct SeqToken {
    /// Whether it is the start of a sequence or the start of an item.
    typ: SeqTokenType,
    /// The length of the value, as indicated by the starting element,
    /// can be unknown.
    len: Length,
}

/// A stateful device for printing a DICOM data set in sequential order.
/// This is analogous to the `DatasetReader` type for converting data
/// set tokens to bytes.
#[derive(Debug)]
pub struct DataSetWriter<W, E, T> {
    to: W,
    encoder: E,
    text: T,
    seq_tokens: Vec<SeqToken>,
}

impl<W> DataSetWriter<W, Box<dyn EncodeTo<W>>, Box<dyn TextCodec>>
where
    W: Write,
{
    pub fn with_ts_cs(to: W, ts: TransferSyntax, cs: SpecificCharacterSet) -> Result<Self> {
        let encoder = ts
            .encoder_for()
            .ok_or_else(|| Error::UnsupportedTransferSyntax)?;
        let text = cs.codec().ok_or_else(|| Error::UnsupportedCharacterSet)?;
        Ok(DataSetWriter::new(to, encoder, text))
    }
}

impl<W, E, T> DataSetWriter<W, E, T> {
    pub fn new(to: W, encoder: E, text: T) -> Self {
        DataSetWriter {
            to,
            encoder,
            text,
            seq_tokens: Vec::new(),
        }
    }
}

impl<W, E, T> DataSetWriter<W, E, T>
where
    W: Write,
    E: Encode,
    T: TextCodec,
{
    /// Feed the given sequence of tokens which are part of the same data set.
    pub fn write_sequence<I>(&mut self, tokens: I) -> Result<()>
    where
        I: IntoIterator<Item = DataToken>,
    {
        for token in tokens {
            self.write(token)?;
        }

        Ok(())
    }

    /// Feed the given data set token for writing the data set.
    #[inline]
    pub fn write(&mut self, token: DataToken) -> Result<()> {
        // adjust the logic of sequence printing:
        // explicit length sequences or items should not print
        // the respective delimiter

        match token {
            DataToken::SequenceStart { tag: _, len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Sequence,
                    len,
                });
                self.write_stateless(token)?;
                Ok(())
            }
            DataToken::ItemStart { len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Item,
                    len,
                });
                self.write_stateless(token)?;
                Ok(())
            }
            DataToken::ItemEnd => {
                // only write if it's an unknown length item
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Item && seq_start.len.is_undefined() {
                        self.write_stateless(token)?;
                    }
                }
                Ok(())
            }
            DataToken::SequenceEnd => {
                // only write if it's an unknown length sequence
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Sequence && seq_start.len.is_undefined() {
                        self.write_stateless(token)?;
                    }
                }
                Ok(())
            }
            _ => self.write_stateless(token),
        }
    }

    fn write_stateless(&mut self, token: DataToken) -> Result<()> {
        use DataToken::*;
        match token {
            ElementHeader(header) => {
                self.encoder.encode_element_header(&mut self.to, header)?;
            }
            SequenceStart { tag, len } => {
                self.encoder.encode_element_header(
                    &mut self.to,
                    DataElementHeader::new(tag, VR::SQ, len),
                )?;
            }
            SequenceEnd => {
                self.encoder.encode_sequence_delimiter(&mut self.to)?;
            }
            ItemStart { len } => {
                self.encoder.encode_item_header(&mut self.to, len.0)?;
            }
            ItemEnd => {
                self.encoder.encode_item_delimiter(&mut self.to)?;
            }
            PrimitiveValue(value) => {
                // TODO handle strings properly
                self.encoder.encode_primitive(&mut self.to, &value)?;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::super::DataToken;
    use super::DataSetWriter;
    use dicom_core::{Tag, VR, header::{DataElementHeader, Length}, value::PrimitiveValue};
    use dicom_encoding::text::DefaultCharacterSetCodec;
    use dicom_encoding::transfer_syntax::explicit_le::ExplicitVRLittleEndianEncoder;

    fn validate_dataset_writer<I>(tokens: I, ground_truth: &[u8])
    where
        I: IntoIterator<Item = DataToken>,
    {
        let mut raw_out: Vec<u8> = vec![];
        let encoder = ExplicitVRLittleEndianEncoder::default();
        let text = DefaultCharacterSetCodec::default();
        let mut dset_writer = DataSetWriter::new(&mut raw_out, encoder, text);

        dset_writer.write_sequence(tokens).unwrap();

        assert_eq!(raw_out, ground_truth);
    }

    #[test]
    fn write_sequence_explicit() {
        let tokens = vec![
            DataToken::SequenceStart {
                tag: Tag(0x0018, 0x6011),
                len: Length(46),
            },
            DataToken::ItemStart { len: Length(20) },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6014),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::ItemStart { len: Length(10) },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::SequenceEnd,
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0020, 0x4000),
                vr: VR::LT,
                len: Length(4),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
        ];

        #[rustfmt::skip]
        static GROUND_TRUTH: &[u8] = &[
            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
            b'S', b'Q', // VR
            0x00, 0x00, // reserved
            0x2e, 0x00, 0x00, 0x00, // length: 28 + 18 = 46 (#= 2)
            // -- 12 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0x14, 0x00, 0x00, 0x00, // item length: 20 (#= 2)
            // -- 20 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
            // -- 30 --
            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
            // -- 40 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0x0a, 0x00, 0x00, 0x00, // item length: 10 (#= 1)
            // -- 48 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
            // -- 58 --
            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
            b'T', b'E', b'S', b'T', // value = "TEST"
        ];

        validate_dataset_writer(tokens, GROUND_TRUTH);
    }

    #[test]
    fn write_sequence_implicit() {
        let tokens = vec![
            DataToken::SequenceStart {
                tag: Tag(0x0018, 0x6011),
                len: Length::UNDEFINED,
            },
            DataToken::ItemStart { len: Length::UNDEFINED },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6014),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::ItemStart { len: Length::UNDEFINED },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::SequenceEnd,
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0020, 0x4000),
                vr: VR::LT,
                len: Length(4),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
        ];

        #[rustfmt::skip]
        static GROUND_TRUTH: &[u8] = &[
            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
            b'S', b'Q', // VR
            0x00, 0x00, // reserved
            0xff, 0xff, 0xff, 0xff, // length: undefined
            // -- 12 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0xff, 0xff, 0xff, 0xff, // item length: undefined
            // -- 20 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
            // -- 30 --
            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
            // -- 40 --
            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
            // -- 48 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0xff, 0xff, 0xff, 0xff, // item length: undefined
            // -- 56 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
            // -- 66 --
            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
            // -- 74 --
            0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
            // -- 82 --
            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
            b'T', b'E', b'S', b'T', // value = "TEST"
        ];

        validate_dataset_writer(tokens, GROUND_TRUTH);
    }
}
<commit_msg>[parser] apply printer to dataset writer<commit_after>//! Module for the data set reader
use crate::dataset::*;
use crate::error::{DataSetSyntaxError, Error, Result};
use crate::printer::Printer;
use dicom_core::{DataElementHeader, Length, VR};
use dicom_encoding::encode::{Encode, EncodeTo};
use dicom_encoding::text::{SpecificCharacterSet, TextCodec};
use dicom_encoding::TransferSyntax;
use std::io::Write;

/// A writer-specific token representing a sequence or item start.
#[derive(Debug)]
struct SeqToken {
    /// Whether it is the start of a sequence or the start of an item.
    typ: SeqTokenType,
    /// The length of the value, as indicated by the starting element,
    /// can be unknown.
    len: Length,
}

/// A stateful device for printing a DICOM data set in sequential order.
/// This is analogous to the `DatasetReader` type for converting data
/// set tokens to bytes.
#[derive(Debug)]
pub struct DataSetWriter<W, E, T> {
    printer: Printer<W, E, T>,
    seq_tokens: Vec<SeqToken>,
    last_de: Option<DataElementHeader>,
}

impl<W> DataSetWriter<W, Box<dyn EncodeTo<W>>, Box<dyn TextCodec>>
where
    W: Write,
{
    pub fn with_ts_cs(to: W, ts: TransferSyntax, cs: SpecificCharacterSet) -> Result<Self> {
        let encoder = ts
            .encoder_for()
            .ok_or_else(|| Error::UnsupportedTransferSyntax)?;
        let text = cs.codec().ok_or_else(|| Error::UnsupportedCharacterSet)?;
        Ok(DataSetWriter::new(to, encoder, text))
    }
}

impl<W, E, T> DataSetWriter<W, E, T> {
    pub fn new(to: W, encoder: E, text: T) -> Self {
        DataSetWriter {
            printer: Printer::new(to, encoder, text),
            seq_tokens: Vec::new(),
            last_de: None,
        }
    }
}

impl<W, E, T> DataSetWriter<W, E, T>
where
    W: Write,
    E: Encode,
    T: TextCodec,
{
    /// Feed the given sequence of tokens which are part of the same data set.
    pub fn write_sequence<I>(&mut self, tokens: I) -> Result<()>
    where
        I: IntoIterator<Item = DataToken>,
    {
        for token in tokens {
            self.write(token)?;
        }

        Ok(())
    }

    /// Feed the given data set token for writing the data set.
    #[inline]
    pub fn write(&mut self, token: DataToken) -> Result<()> {
        // adjust the logic of sequence printing:
        // explicit length sequences or items should not print
        // the respective delimiter

        match token {
            DataToken::SequenceStart { tag: _, len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Sequence,
                    len,
                });
                self.write_impl(token)?;
                Ok(())
            }
            DataToken::ItemStart { len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Item,
                    len,
                });
                self.write_impl(token)?;
                Ok(())
            }
            DataToken::ItemEnd => {
                // only write if it's an unknown length item
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Item && seq_start.len.is_undefined() {
                        self.write_impl(token)?;
                    }
                }
                Ok(())
            }
            DataToken::SequenceEnd => {
                // only write if it's an unknown length sequence
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Sequence && seq_start.len.is_undefined() {
                        self.write_impl(token)?;
                    }
                }
                Ok(())
            }
            DataToken::ElementHeader(de) => {
                self.last_de = Some(de.clone());
                self.write_impl(token)
            }
            _ => {
                self.write_impl(token)
            }
        }
    }

    fn write_impl(&mut self, token: DataToken) -> Result<()> {
        use DataToken::*;
        match token {
            ElementHeader(header) => {
                self.printer.encode_element_header(header)?;
            }
            SequenceStart { tag, len } => {
                self.printer.encode_element_header(
                    DataElementHeader::new(tag, VR::SQ, len),
                )?;
            }
            SequenceEnd => {
                self.printer.encode_sequence_delimiter()?;
            }
            ItemStart { len } => {
                self.printer.encode_item_header(len.0)?;
            }
            ItemEnd => {
                self.printer.encode_item_delimiter()?;
            }
            PrimitiveValue(ref value) => {
                let last_de = self.last_de.as_ref()
                    .ok_or_else(|| DataSetSyntaxError::UnexpectedToken(token.clone()))?;
                self.printer.encode_primitive(last_de, value)?;
                self.last_de = None;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::super::DataToken;
    use super::DataSetWriter;
    use dicom_core::{Tag, VR, header::{DataElementHeader, Length}, value::PrimitiveValue};
    use dicom_encoding::text::DefaultCharacterSetCodec;
    use dicom_encoding::transfer_syntax::explicit_le::ExplicitVRLittleEndianEncoder;

    fn validate_dataset_writer<I>(tokens: I, ground_truth: &[u8])
    where
        I: IntoIterator<Item = DataToken>,
    {
        let mut raw_out: Vec<u8> = vec![];
        let encoder = ExplicitVRLittleEndianEncoder::default();
        let text = DefaultCharacterSetCodec::default();
        let mut dset_writer = DataSetWriter::new(&mut raw_out, encoder, text);

        dset_writer.write_sequence(tokens).unwrap();

        assert_eq!(raw_out, ground_truth);
    }

    #[test]
    fn write_sequence_explicit() {
        let tokens = vec![
            DataToken::SequenceStart {
                tag: Tag(0x0018, 0x6011),
                len: Length(46),
            },
            DataToken::ItemStart { len: Length(20) },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6014),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::ItemStart { len: Length(10) },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::SequenceEnd,
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0020, 0x4000),
                vr: VR::LT,
                len: Length(4),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
        ];

        #[rustfmt::skip]
        static GROUND_TRUTH: &[u8] = &[
            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
            b'S', b'Q', // VR
            0x00, 0x00, // reserved
            0x2e, 0x00, 0x00, 0x00, // length: 28 + 18 = 46 (#= 2)
            // -- 12 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0x14, 0x00, 0x00, 0x00, // item length: 20 (#= 2)
            // -- 20 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
            // -- 30 --
            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
            // -- 40 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0x0a, 0x00, 0x00, 0x00, // item length: 10 (#= 1)
            // -- 48 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
            // -- 58 --
            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
            b'T', b'E', b'S', b'T', // value = "TEST"
        ];

        validate_dataset_writer(tokens, GROUND_TRUTH);
    }

    #[test]
    fn write_sequence_implicit() {
        let tokens = vec![
            DataToken::SequenceStart {
                tag: Tag(0x0018, 0x6011),
                len: Length::UNDEFINED,
            },
            DataToken::ItemStart { len: Length::UNDEFINED },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6014),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::ItemStart { len: Length::UNDEFINED },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::SequenceEnd,
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0020, 0x4000),
                vr: VR::LT,
                len: Length(4),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
        ];

        #[rustfmt::skip]
        static GROUND_TRUTH: &[u8] = &[
            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
            b'S', b'Q', // VR
            0x00, 0x00, // reserved
            0xff, 0xff, 0xff, 0xff, // length: undefined
            // -- 12 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0xff, 0xff, 0xff, 0xff, // item length: undefined
            // -- 20 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
            // -- 30 --
            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
            // -- 40 --
            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
            // -- 48 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0xff, 0xff, 0xff, 0xff, // item length: undefined
            // -- 56 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
            // -- 66 --
            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
            // -- 74 --
            0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
            // -- 82 --
            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
            b'T', b'E', b'S', b'T', // value = "TEST"
        ];

        validate_dataset_writer(tokens, GROUND_TRUTH);
    }
}
<|endoftext|>


<commit_before>//! The macros in this module can implement the serialisation traits for rust structs,
//! as if they were ASN.1 Sequences.
//!
//! You can either use the shortcut asn1_sequence! macro, or each of
//! asn1_sequence_info!, asn1_sequence_serialize! and asn1_sequence_deserialize!.
//!
//! ```
//! #[macro_use] extern crate asn1_cereal; fn main() {
//!   struct ShortSequence {
//!     z: u64,
//!     y: u32,
//!   }
//!
//!   asn1_sequence!(
//!     ShortSequence,
//!     "SHORT_SEQUENCE",
//!     z,
//!     y
//!   );
//!
//!   // OR
//!
//!   struct SomeSequence {
//!     a: u64,
//!     b: u32,
//!     c: String,
//!   }
//!
//!   asn1_sequence_info!(SomeSequence, "SOME_SEQUENCE");
//!   asn1_sequence_serialize!(SomeSequence, a, b, c);
//!   asn1_sequence_deserialize!(SomeSequence, a, b, c);
//! }
//! ```
//!
//! Note that these macros won't handle SEQUENCE OF.

#[macro_export]
/// This macro is a compact way of defining all three of the
/// Asn1 traits - Asn1Info, Asn1Serialize and Asn1Deserialize -
/// for a rust struct, that represents an ASN.1 sequence.
///
/// Note that the order the fields are placed in will affect the order
/// that they are encoded to, and decoded from ASN.1. If some form of
/// procedural macros are eventually stabilised, listing the fields
/// in the macro might no longer be required.
macro_rules! asn1_sequence {
  ($rs_type:ident, $asn1_ty:expr, $($item:ident),*) => (
    asn1_sequence_info!($rs_type, $asn1_ty);
    asn1_sequence_serialize!($rs_type, $($item),*);
    asn1_sequence_deserialize!($rs_type, $($item),*);
  )
}

#[macro_export]
/// This macro defines the Asn1Info trait for a rust struct. This allows the other
/// traits to get information about this type. If you need to provide a custom
/// class or tag, consider using the asn1_info! macro.
macro_rules! asn1_sequence_info {
  ($rs_type:ident, $asn1_ty:expr) => (
    impl $crate::serial::Asn1Info for $rs_type {
      fn asn1_tag() -> $crate::tag::Tag {
        $crate::tag::Tag {
          class: $crate::tag::Class::Universal,
          tagnum: (0x10 as u8).into(),
          constructed: true,
        }
      }

      fn asn1_type() -> $crate::tag::Type {
        $asn1_ty.into()
      }
    }
  )
}

#[macro_export]
/// This macro defines the Asn1Serialize trait for a rust struct. The code generated
/// will serialize the specified fields in the order that they are given.
macro_rules! asn1_sequence_serialize {
  ($rs_type:ty, $($item:ident),*) => (
    impl $crate::serial::Asn1Serialize for $rs_type {
      fn serialize_bytes<E: $crate::enc::Asn1EncRules, W: std::io::Write>
          (&self, e: E, writer: &mut W) -> Result<(), $crate::err::EncodeError> {
        let mut bytes = Vec::new();
        let mut count: u64 = 0;
        // For each declared sequence member, serialize it onto the stream.
        $(
          count += 1;
          // If encoding uses implicit tag, skip context-specific tag.
          if E::tag_rules() == $crate::enc::TagEnc::Implicit {
            try!($crate::serial::Asn1Serialize::serialize_enc(&self.$item, e, writer));
          // Otherwise encode the context-specific tag.
          } else {
            try!($crate::serial::Asn1Serialize::serialize_enc(&self.$item, e, &mut bytes));
            let tag = $crate::tag::TagLen {
              tag: $crate::tag::Tag {
                class: $crate::tag::Class::ContextSpecific,
                tagnum: count.into(),
                constructed: true,
              },
              len: Some(bytes.len() as $crate::tag::LenNum).into(),
            };
            try!(tag.write_taglen(writer));
            try!(writer.write_all(&mut bytes));

            bytes.clear();
          }
        )*
        Ok(())
      }
    }
  )
}

#[macro_export]
/// This macro defines the Asn1Deserialize trait for a rust struct. The code generated
/// will deserialize the specified fields in the order that they are given.
macro_rules! asn1_sequence_deserialize {
  ($rs_type:ident, $($item:ident),*) => (
    impl $crate::serial::Asn1Deserialize for $rs_type {
      fn deserialize_bytes<E: $crate::enc::Asn1EncRules, I: Iterator<Item=std::io::Result<u8>>>
          (e: E, reader: &mut I, _: Option<$crate::tag::LenNum>) -> Result<Self, $crate::err::DecodeError> {
        let mut count: u64 = 0;
        Ok( $rs_type { $(
          $item: {
            count += 1;
            let our_tag = $crate::tag::Tag {
              class: $crate::tag::Class::ContextSpecific,
              tagnum: count.into(),
              constructed: true,
            };
            let tag = try!($crate::tag::Tag::read_tag(reader));

            // If encoding uses implicit tagging, throw an error if this isn't an implicit tag.
            if E::tag_rules() == $crate::enc::TagEnc::Implicit && tag == our_tag {
              return Err($crate::err::DecodeError::ExplicitTag);
            }

            // If the tag matches our tag, decode the len and call the normal deserialize function.
            if tag == our_tag {
              let _ = try!($crate::tag::Len::read_len(reader));
              try!($crate::serial::Asn1Deserialize::deserialize_enc(e, reader))
            // Otherwise decode it as the inner type.
            } else {
              try!($crate::serial::Asn1Deserialize::deserialize_enc_tag(e, reader, tag))
            }
          },
        )* })
      }
    }
  )
}
<commit_msg>Update sequence deserialize macro to use variables<commit_after>//! The macros in this module can implement the serialisation traits for rust structs,
//! as if they were ASN.1 Sequences.
//!
//! You can either use the shortcut asn1_sequence! macro, or each of
//! asn1_sequence_info!, asn1_sequence_serialize! and asn1_sequence_deserialize!.
//!
//! ```
//! #[macro_use] extern crate asn1_cereal; fn main() {
//!   struct ShortSequence {
//!     z: u64,
//!     y: u32,
//!   }
//!
//!   asn1_sequence!(
//!     ShortSequence,
//!     "SHORT_SEQUENCE",
//!     z,
//!     y
//!   );
//!
//!   // OR
//!
//!   struct SomeSequence {
//!     a: u64,
//!     b: u32,
//!     c: String,
//!   }
//!
//!   asn1_sequence_info!(SomeSequence, "SOME_SEQUENCE");
//!   asn1_sequence_serialize!(SomeSequence, a, b, c);
//!   asn1_sequence_deserialize!(SomeSequence, a, b, c);
//! }
//! ```
//!
//! Note that these macros won't handle SEQUENCE OF.

#[macro_export]
/// This macro is a compact way of defining all three of the
/// Asn1 traits - Asn1Info, Asn1Serialize and Asn1Deserialize -
/// for a rust struct, that represents an ASN.1 sequence.
///
/// Note that the order the fields are placed in will affect the order
/// that they are encoded to, and decoded from ASN.1. If some form of
/// procedural macros are eventually stabilised, listing the fields
/// in the macro might no longer be required.
macro_rules! asn1_sequence {
  ($rs_type:ident, $asn1_ty:expr, $($item:ident),*) => (
    asn1_sequence_info!($rs_type, $asn1_ty);
    asn1_sequence_serialize!($rs_type, $($item),*);
    asn1_sequence_deserialize!($rs_type, $($item),*);
  )
}

#[macro_export]
/// This macro defines the Asn1Info trait for a rust struct. This allows the other
/// traits to get information about this type. If you need to provide a custom
/// class or tag, consider using the asn1_info! macro.
macro_rules! asn1_sequence_info {
  ($rs_type:ident, $asn1_ty:expr) => (
    impl $crate::serial::Asn1Info for $rs_type {
      fn asn1_tag() -> $crate::tag::Tag {
        $crate::tag::Tag {
          class: $crate::tag::Class::Universal,
          tagnum: (0x10 as u8).into(),
          constructed: true,
        }
      }

      fn asn1_type() -> $crate::tag::Type {
        $asn1_ty.into()
      }
    }
  )
}

#[macro_export]
/// This macro defines the Asn1Serialize trait for a rust struct. The code generated
/// will serialize the specified fields in the order that they are given.
macro_rules! asn1_sequence_serialize {
  ($rs_type:ty, $($item:ident),*) => (
    impl $crate::serial::Asn1Serialize for $rs_type {
      fn serialize_bytes<E: $crate::enc::Asn1EncRules, W: std::io::Write>
          (&self, e: E, writer: &mut W) -> Result<(), $crate::err::EncodeError> {
        let mut bytes = Vec::new();
        let mut count: u64 = 0;
        // For each declared sequence member, serialize it onto the stream.
        $(
          count += 1;
          // If encoding uses implicit tag, skip context-specific tag.
          if E::tag_rules() == $crate::enc::TagEnc::Implicit {
            try!($crate::serial::Asn1Serialize::serialize_enc(&self.$item, e, writer));
          // Otherwise encode the context-specific tag.
          } else {
            try!($crate::serial::Asn1Serialize::serialize_enc(&self.$item, e, &mut bytes));
            let tag = $crate::tag::TagLen {
              tag: $crate::tag::Tag {
                class: $crate::tag::Class::ContextSpecific,
                tagnum: count.into(),
                constructed: true,
              },
              len: Some(bytes.len() as $crate::tag::LenNum).into(),
            };
            try!(tag.write_taglen(writer));
            try!(writer.write_all(&mut bytes));

            bytes.clear();
          }
        )*
        Ok(())
      }
    }
  )
}

#[macro_export]
/// This macro defines the Asn1Deserialize trait for a rust struct. The code generated
/// will deserialize the specified fields in the order that they are given.
macro_rules! asn1_sequence_deserialize {
  ($rs_type:ident, $($item:ident),*) => (
    impl $crate::serial::Asn1Deserialize for $rs_type {
      fn deserialize_bytes<E: $crate::enc::Asn1EncRules, I: Iterator<Item=std::io::Result<u8>>>
          (e: E, reader: &mut I, _: Option<$crate::tag::LenNum>) -> Result<Self, $crate::err::DecodeError> {
        let mut count: u64 = 0;
        $(
          // Iterate count.
          // FIXME: Does this start from 0 or 1?
          count += 1;

          // Use field name as variable name, due to hygiene this won't conflict with any
          // defined locally.
          let $item;
          {
            // Create a copy of what our tag context-specific tag would look like.
            let our_tag = $crate::tag::Tag {
              class: $crate::tag::Class::ContextSpecific,
              tagnum: count.into(),
              constructed: true,
            };
            let tag = try!($crate::tag::Tag::read_tag(reader));

            // If encoding uses implicit tagging, throw an error if this isn't an implicit tag.
            if E::tag_rules() == $crate::enc::TagEnc::Implicit && tag == our_tag {
              return Err($crate::err::DecodeError::ExplicitTag);
            }

            // If the tag matches our tag, decode the len and call the normal deserialize function.
            $item = if tag == our_tag {
              // We don't have anything to do with this, technically we should use it to
              // check the length decoded.
              let _ = try!($crate::tag::Len::read_len(reader));
              try!($crate::serial::Asn1Deserialize::deserialize_enc(e, reader))
            // Otherwise decode it as the inner type. (We give the tag that we
            // decoded, and the function will decode the length itself).
            } else {
              try!($crate::serial::Asn1Deserialize::deserialize_enc_tag(e, reader, tag))
            };
          }
        )*
        Ok( $rs_type { $(
          $item: $item,
        )* })
      }
    }
  )
}
<|endoftext|>