<commit_before>use capnp::message;
use hyper::{Client, Url};
use hyper::client::Body;
use hyper::header::Expect;
use hyper::status::StatusCode;
use rand;
use rustc_serialize::json;
use time;
use time::{Duration, Timespec};

use ::cache::{Cache, FileHasher};
use ::io::memstream::MemStream;
use ::io::statistic::Statistic;
use ::cluster::common::{BuilderInfo, RPC_BUILDER_LIST, RPC_BUILDER_TASK, RPC_BUILDER_UPLOAD};
use ::cluster::builder::{CompileRequest, CompileResponse};
use ::compiler::{CommandInfo, CompilationTask, CompileStep, Compiler, OutputInfo, PreprocessResult, Toolchain};

use std::fs;
use std::fs::File;
use std::io::{BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::net::SocketAddr;

pub struct RemoteCompiler<C: Compiler> {
    shared: Arc<RemoteShared>,
    local: C,
}

struct RemoteSharedMut {
    cooldown: Timespec,
    builders: Arc<Vec<BuilderInfo>>,
}

struct RemoteShared {
    mutable: RwLock<RemoteSharedMut>,
    base_url: Option<Url>,
    statistic: Arc<Statistic>,
    cache: Arc<Cache>,
    client: Client,
}

struct RemoteToolchain {
    shared: Arc<RemoteShared>,
    local: Arc<Toolchain>,
}

impl<C: Compiler> RemoteCompiler<C> {
    pub fn new(base_url: &Option<Url>, compiler: C, cache: &Arc<Cache>, statistic: &Arc<Statistic>) -> Self {
        RemoteCompiler {
            shared: Arc::new(RemoteShared {
                mutable: RwLock::new(RemoteSharedMut {
                    cooldown: Timespec { sec: 0, nsec: 0 },
                    builders: Arc::new(Vec::new()),
                }),
                base_url: base_url.as_ref().map(|u| u.clone()),
                cache: cache.clone(),
                statistic: statistic.clone(),
                client: Client::new(),
            }),
            local: compiler,
        }
    }
}

impl RemoteSharedMut {
    fn receive_builders(&self, base_url: &Option<Url>) -> Result<Vec<BuilderInfo>, Error> {
        match base_url {
            &Some(ref base_url) => {
                let client = Client::new();
                client.get(base_url.join(RPC_BUILDER_LIST).unwrap())
                    .send()
                    .map_err(|e| Error::new(ErrorKind::Other, e))
                    .and_then(|mut response| {
                        let mut payload = String::new();
                        response.read_to_string(&mut payload).map(|_| payload)
                    })
                    .and_then(|payload| json::decode(&payload).map_err(|e| Error::new(ErrorKind::InvalidData, e)))
            }
            &None => Ok(Vec::new()),
        }
    }
}

impl<C: Compiler> Compiler for RemoteCompiler<C> {
    // Discovery local toolchains.
    fn discovery_toolchains(&self) -> Vec<Arc<Toolchain>> {
        self.local.discovery_toolchains()
    }

    // Resolve toolchain for command execution.
    fn resolve_toolchain(&self, command: &CommandInfo) -> Option<Arc<Toolchain>> {
        self.local
            .resolve_toolchain(command)
            .map(|local| -> Arc<Toolchain> {
                Arc::new(RemoteToolchain {
                    shared: self.shared.clone(),
                    local: local,
                })
            })
    }
}

struct ReadWrapper<'a, R: 'a + Read>(&'a mut R);

impl<'a, R: 'a + Read> Read for ReadWrapper<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        self.0.read(buf)
    }
}

impl RemoteToolchain {
    fn compile_remote(&self, task: &CompileStep) -> Result<CompileResponse, Error> {
        let name = try!(self.identifier().ok_or(Error::new(ErrorKind::Other, "Can't get toolchain name")));
        let addr = try!(self.remote_endpoint(&name)
            .ok_or(Error::new(ErrorKind::Other, "Can't find helper for toolchain")));
        if task.output_precompiled.is_some() {
            return Err(Error::new(ErrorKind::Other,
                                  "Remote precompiled header generation is not supported"));
        }

        let base_url = get_base_url(&addr);
        // Send compilation request.
        let request = CompileRequest {
            toolchain: name.clone(),
            args: task.args.clone(),
            preprocessed_data: (&task.preprocessed).into(),
            precompiled_hash: try!(self.upload_precompiled(&task.input_precompiled, &base_url)),
        };
        let mut request_payload = Vec::new();
        try!(request.stream_write(&mut request_payload, &mut message::Builder::new_default()));
        self.shared
            .client
            .post(base_url.join(RPC_BUILDER_TASK)
                .unwrap())
            .body(&request_payload[..])
            .send()
            .map_err(|e| Error::new(ErrorKind::Other, e))
            .and_then(|mut response| {
                // Receive compilation result.
                let mut options = ::capnp::message::ReaderOptions::new();
                options.traversal_limit_in_words(1024 * 1024 * 1024);
                CompileResponse::stream_read(&mut BufReader::new(ReadWrapper(&mut response)), options)
                    .map_err(|e| Error::new(ErrorKind::InvalidData, e))
                    .and_then(|result| {
                        match result {
                            CompileResponse::Success(ref output, ref content) => {
                                try!(write_output(&task.output_object, output.success(), content));
                            }
                            _ => {}
                        }
                        self.shared.statistic.inc_remote();
                        Ok(result)
                    })
            })
    }

    fn upload_precompiled(&self, precompiled: &Option<PathBuf>, base_url: &Url) -> Result<Option<String>, Error> {
        match precompiled {
            &Some(ref path) => {
                // Get precompiled header file hash
                let meta = try!(self.shared.cache.file_hash(&path));
                // Check is precompiled header uploaded
                // todo: this is workaround for https://github.com/hyperium/hyper/issues/838
                match try!(self.shared
                    .client
                    .head(base_url.join(&format!("{}/{}", RPC_BUILDER_UPLOAD, meta.hash))
                        .unwrap())
                    .send()
                    .map(|response| response.status)
                    .map_err(|e| Error::new(ErrorKind::BrokenPipe, e))) {
                    StatusCode::Ok | StatusCode::Accepted => return Ok(Some(meta.hash)),
                    _ => {}
                }
                println!("Upload: {}, {}, {}",
                         path.file_name().unwrap().to_string_lossy(),
                         meta.hash,
                         meta.size);
                let mut file = try!(File::open(path));
                // Upload precompiled header
                match try!(self.shared
                    .client
                    .post(base_url.join(&format!("{}/{}", RPC_BUILDER_UPLOAD, meta.hash))
                        .unwrap())
                    //.header(Expect::Continue) // todo: this is workaround for https://github.com/hyperium/hyper/issues/838
                    .body(Body::SizedBody(&mut file, meta.size))
                    .send()
                    .map(|response| response.status)
                    .map_err(|e| Error::new(ErrorKind::BrokenPipe, e))) {
                    StatusCode::Ok | StatusCode::Accepted => Ok(Some(meta.hash)),
                    status => {
                        Err(Error::new(ErrorKind::BrokenPipe,
                                       format!("Can't upload precompiled header: {}", status)))
                    }
                }
            }
            &None => Ok(None),
        }
    }

    fn builders(&self) -> Arc<Vec<BuilderInfo>> {
        let now = time::get_time();
        {
            let holder = self.shared.mutable.read().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
        }
        {
            let mut holder = self.shared.mutable.write().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
            match holder.receive_builders(&self.shared.base_url) {
                Ok(builders) => {
                    holder.builders = Arc::new(builders);
                    holder.cooldown = now + Duration::seconds(5);
                }
                Err(e) => {
                    holder.cooldown = now + Duration::seconds(1);
                    warn!("Can't receive toolchains from coordinator: {}", e);
                }
            }
            return holder.builders.clone();
        }
    }
    // Resolve toolchain for command execution.
    fn remote_endpoint(&self, toolchain_name: &str) -> Option<SocketAddr> {
        let name = toolchain_name.to_string();
        let all_builders = self.builders();
        get_random_builder(&all_builders, |b| b.toolchains.contains(&name))
            .and_then(|builder| SocketAddr::from_str(&builder.endpoint).ok())
    }
}

impl Toolchain for RemoteToolchain {
    fn identifier(&self) -> Option<String> {
        self.local.identifier()
    }

    // Parse compiler arguments.
    fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<Option<CompilationTask>, String> {
        self.local.create_task(command, args)
    }

    // Preprocessing source file.
    fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
        self.local.preprocess_step(task)
    }

    // Compile preprocessed file.
    fn compile_prepare_step(&self, task: CompilationTask, preprocessed: MemStream) -> Result<CompileStep, Error> {
        self.local.compile_prepare_step(task, preprocessed)
    }

    fn compile_step(&self, task: CompileStep) -> Result<OutputInfo, Error> {
        match self.compile_remote(&task) {
            Ok(response) => {
                match response {
                    CompileResponse::Success(output, _) => Ok(output),
                    CompileResponse::Err(err) => Err(err),
                }
            }
            Err(e) => {
                trace!("Fallback to local build: {}", e);
                self.local.compile_step(task)
            }
        }
    }
}

fn get_base_url(addr: &SocketAddr) -> Url {
    let mut url = Url::from_str("http://localhost").unwrap();
    url.set_ip_host(addr.ip()).unwrap();
    url.set_port(Some(addr.port())).unwrap();
    url
}

fn write_output(path: &Option<PathBuf>, success: bool, output: &[u8]) -> Result<(), Error> {
    match path {
        &Some(ref path) => {
            match success {
                true => {
                    File::create(path)
                        .and_then(|mut f| f.write(&output))
                        .or_else(|e| {
                            drop(fs::remove_file(path));
                            Err(e)
                        })
                        .map(|_| ())
                }
                false => fs::remove_file(path),
            }
        }
        &None => Ok(()),
    }
}

fn get_random_builder<F: Fn(&BuilderInfo) -> bool>(builders: &Vec<BuilderInfo>, filter: F) -> Option<&BuilderInfo> {
    let filtered: Vec<&BuilderInfo> = builders.iter().filter(|b| filter(b)).collect();
    if filtered.len() > 0 {
        Some(filtered[rand::random::<usize>() % filtered.len()].clone())
    } else {
        None
    }
}
<commit_msg>Remove debug output<commit_after>use capnp::message;
use hyper::{Client, Url};
use hyper::client::Body;
use hyper::header::Expect;
use hyper::status::StatusCode;
use rand;
use rustc_serialize::json;
use time;
use time::{Duration, Timespec};

use ::cache::{Cache, FileHasher};
use ::io::memstream::MemStream;
use ::io::statistic::Statistic;
use ::cluster::common::{BuilderInfo, RPC_BUILDER_LIST, RPC_BUILDER_TASK, RPC_BUILDER_UPLOAD};
use ::cluster::builder::{CompileRequest, CompileResponse};
use ::compiler::{CommandInfo, CompilationTask, CompileStep, Compiler, OutputInfo, PreprocessResult, Toolchain};

use std::fs;
use std::fs::File;
use std::io::{BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::net::SocketAddr;

pub struct RemoteCompiler<C: Compiler> {
    shared: Arc<RemoteShared>,
    local: C,
}

struct RemoteSharedMut {
    cooldown: Timespec,
    builders: Arc<Vec<BuilderInfo>>,
}

struct RemoteShared {
    mutable: RwLock<RemoteSharedMut>,
    base_url: Option<Url>,
    statistic: Arc<Statistic>,
    cache: Arc<Cache>,
    client: Client,
}

struct RemoteToolchain {
    shared: Arc<RemoteShared>,
    local: Arc<Toolchain>,
}

impl<C: Compiler> RemoteCompiler<C> {
    pub fn new(base_url: &Option<Url>, compiler: C, cache: &Arc<Cache>, statistic: &Arc<Statistic>) -> Self {
        RemoteCompiler {
            shared: Arc::new(RemoteShared {
                mutable: RwLock::new(RemoteSharedMut {
                    cooldown: Timespec { sec: 0, nsec: 0 },
                    builders: Arc::new(Vec::new()),
                }),
                base_url: base_url.as_ref().map(|u| u.clone()),
                cache: cache.clone(),
                statistic: statistic.clone(),
                client: Client::new(),
            }),
            local: compiler,
        }
    }
}

impl RemoteSharedMut {
    fn receive_builders(&self, base_url: &Option<Url>) -> Result<Vec<BuilderInfo>, Error> {
        match base_url {
            &Some(ref base_url) => {
                let client = Client::new();
                client.get(base_url.join(RPC_BUILDER_LIST).unwrap())
                    .send()
                    .map_err(|e| Error::new(ErrorKind::Other, e))
                    .and_then(|mut response| {
                        let mut payload = String::new();
                        response.read_to_string(&mut payload).map(|_| payload)
                    })
                    .and_then(|payload| json::decode(&payload).map_err(|e| Error::new(ErrorKind::InvalidData, e)))
            }
            &None => Ok(Vec::new()),
        }
    }
}

impl<C: Compiler> Compiler for RemoteCompiler<C> {
    // Discovery local toolchains.
    fn discovery_toolchains(&self) -> Vec<Arc<Toolchain>> {
        self.local.discovery_toolchains()
    }

    // Resolve toolchain for command execution.
    fn resolve_toolchain(&self, command: &CommandInfo) -> Option<Arc<Toolchain>> {
        self.local
            .resolve_toolchain(command)
            .map(|local| -> Arc<Toolchain> {
                Arc::new(RemoteToolchain {
                    shared: self.shared.clone(),
                    local: local,
                })
            })
    }
}

struct ReadWrapper<'a, R: 'a + Read>(&'a mut R);

impl<'a, R: 'a + Read> Read for ReadWrapper<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        self.0.read(buf)
    }
}

impl RemoteToolchain {
    fn compile_remote(&self, task: &CompileStep) -> Result<CompileResponse, Error> {
        let name = try!(self.identifier().ok_or(Error::new(ErrorKind::Other, "Can't get toolchain name")));
        let addr = try!(self.remote_endpoint(&name)
            .ok_or(Error::new(ErrorKind::Other, "Can't find helper for toolchain")));
        if task.output_precompiled.is_some() {
            return Err(Error::new(ErrorKind::Other,
                                  "Remote precompiled header generation is not supported"));
        }

        let base_url = get_base_url(&addr);
        // Send compilation request.
        let request = CompileRequest {
            toolchain: name.clone(),
            args: task.args.clone(),
            preprocessed_data: (&task.preprocessed).into(),
            precompiled_hash: try!(self.upload_precompiled(&task.input_precompiled, &base_url)),
        };
        let mut request_payload = Vec::new();
        try!(request.stream_write(&mut request_payload, &mut message::Builder::new_default()));
        self.shared
            .client
            .post(base_url.join(RPC_BUILDER_TASK)
                .unwrap())
            .body(&request_payload[..])
            .send()
            .map_err(|e| Error::new(ErrorKind::Other, e))
            .and_then(|mut response| {
                // Receive compilation result.
                let mut options = ::capnp::message::ReaderOptions::new();
                options.traversal_limit_in_words(1024 * 1024 * 1024);
                CompileResponse::stream_read(&mut BufReader::new(ReadWrapper(&mut response)), options)
                    .map_err(|e| Error::new(ErrorKind::InvalidData, e))
                    .and_then(|result| {
                        match result {
                            CompileResponse::Success(ref output, ref content) => {
                                try!(write_output(&task.output_object, output.success(), content));
                            }
                            _ => {}
                        }
                        self.shared.statistic.inc_remote();
                        Ok(result)
                    })
            })
    }

    fn upload_precompiled(&self, precompiled: &Option<PathBuf>, base_url: &Url) -> Result<Option<String>, Error> {
        match precompiled {
            &Some(ref path) => {
                // Get precompiled header file hash
                let meta = try!(self.shared.cache.file_hash(&path));
                // Check is precompiled header uploaded
                // todo: this is workaround for https://github.com/hyperium/hyper/issues/838
                match try!(self.shared
                    .client
                    .head(base_url.join(&format!("{}/{}", RPC_BUILDER_UPLOAD, meta.hash))
                        .unwrap())
                    .send()
                    .map(|response| response.status)
                    .map_err(|e| Error::new(ErrorKind::BrokenPipe, e))) {
                    StatusCode::Ok | StatusCode::Accepted => return Ok(Some(meta.hash)),
                    _ => {}
                }
                let mut file = try!(File::open(path));
                // Upload precompiled header
                match try!(self.shared
                    .client
                    .post(base_url.join(&format!("{}/{}", RPC_BUILDER_UPLOAD, meta.hash))
                        .unwrap())
                    //.header(Expect::Continue) // todo: this is workaround for https://github.com/hyperium/hyper/issues/838
                    .body(Body::SizedBody(&mut file, meta.size))
                    .send()
                    .map(|response| response.status)
                    .map_err(|e| Error::new(ErrorKind::BrokenPipe, e))) {
                    StatusCode::Ok | StatusCode::Accepted => Ok(Some(meta.hash)),
                    status => {
                        Err(Error::new(ErrorKind::BrokenPipe,
                                       format!("Can't upload precompiled header: {}", status)))
                    }
                }
            }
            &None => Ok(None),
        }
    }

    fn builders(&self) -> Arc<Vec<BuilderInfo>> {
        let now = time::get_time();
        {
            let holder = self.shared.mutable.read().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
        }
        {
            let mut holder = self.shared.mutable.write().unwrap();
            if holder.cooldown >= now {
                return holder.builders.clone();
            }
            match holder.receive_builders(&self.shared.base_url) {
                Ok(builders) => {
                    holder.builders = Arc::new(builders);
                    holder.cooldown = now + Duration::seconds(5);
                }
                Err(e) => {
                    holder.cooldown = now + Duration::seconds(1);
                    warn!("Can't receive toolchains from coordinator: {}", e);
                }
            }
            return holder.builders.clone();
        }
    }
    // Resolve toolchain for command execution.
    fn remote_endpoint(&self, toolchain_name: &str) -> Option<SocketAddr> {
        let name = toolchain_name.to_string();
        let all_builders = self.builders();
        get_random_builder(&all_builders, |b| b.toolchains.contains(&name))
            .and_then(|builder| SocketAddr::from_str(&builder.endpoint).ok())
    }
}

impl Toolchain for RemoteToolchain {
    fn identifier(&self) -> Option<String> {
        self.local.identifier()
    }

    // Parse compiler arguments.
    fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<Option<CompilationTask>, String> {
        self.local.create_task(command, args)
    }

    // Preprocessing source file.
    fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
        self.local.preprocess_step(task)
    }

    // Compile preprocessed file.
    fn compile_prepare_step(&self, task: CompilationTask, preprocessed: MemStream) -> Result<CompileStep, Error> {
        self.local.compile_prepare_step(task, preprocessed)
    }

    fn compile_step(&self, task: CompileStep) -> Result<OutputInfo, Error> {
        match self.compile_remote(&task) {
            Ok(response) => {
                match response {
                    CompileResponse::Success(output, _) => Ok(output),
                    CompileResponse::Err(err) => Err(err),
                }
            }
            Err(e) => {
                trace!("Fallback to local build: {}", e);
                self.local.compile_step(task)
            }
        }
    }
}

fn get_base_url(addr: &SocketAddr) -> Url {
    let mut url = Url::from_str("http://localhost").unwrap();
    url.set_ip_host(addr.ip()).unwrap();
    url.set_port(Some(addr.port())).unwrap();
    url
}

fn write_output(path: &Option<PathBuf>, success: bool, output: &[u8]) -> Result<(), Error> {
    match path {
        &Some(ref path) => {
            match success {
                true => {
                    File::create(path)
                        .and_then(|mut f| f.write(&output))
                        .or_else(|e| {
                            drop(fs::remove_file(path));
                            Err(e)
                        })
                        .map(|_| ())
                }
                false => fs::remove_file(path),
            }
        }
        &None => Ok(()),
    }
}

fn get_random_builder<F: Fn(&BuilderInfo) -> bool>(builders: &Vec<BuilderInfo>, filter: F) -> Option<&BuilderInfo> {
    let filtered: Vec<&BuilderInfo> = builders.iter().filter(|b| filter(b)).collect();
    if filtered.len() > 0 {
        Some(filtered[rand::random::<usize>() % filtered.len()].clone())
    } else {
        None
    }
}
<|endoftext|>


<commit_before>//! Codec for chunk type 11 = FLI_COLOR64.

use std::io::{Cursor,Read,Seek,SeekFrom,Write};
use byteorder::LittleEndian as LE;
use byteorder::{ReadBytesExt,WriteBytesExt};

use ::{FlicError,FlicResult,Raster,RasterMut};
use super::{Group,GroupByEq};

/// Magic for a FLI_COLOR64 chunk - 64-Level Color.
///
/// This chunk is identical to FLI_COLOR256 except that the values for
/// the red, green and blue components are in the range of 0-63
/// instead of 0-255.
pub const FLI_COLOR64: u16 = 11;

/// Decode a FLI_COLOR64 chunk.
pub fn decode_fli_color64(src: &[u8], dst: &mut RasterMut)
        -> FlicResult<()> {
    let mut r = Cursor::new(src);
    let mut idx0 = 0;

    let count = try!(r.read_u16::<LE>());
    for _ in 0..count {
        let nskip = try!(r.read_u8()) as usize;
        let ncopy = match try!(r.read_u8()) {
            0 => 256 as usize,
            n => n as usize,
        };

        let start = idx0 + 3 * nskip;
        let end = start + 3 * ncopy;
        if end > dst.pal.len() {
            return Err(FlicError::Corrupted);
        }

        try!(r.read_exact(&mut dst.pal[start..end]));
        for i in start..end {
            if dst.pal[i] > ::std::u8::MAX / 4 {
                return Err(FlicError::Corrupted);
            }

            dst.pal[i] = 4 * dst.pal[i];
        }

        idx0 = end;
    }

    Ok(())
}

/// Encode a FLI_COLOR64 chunk.
pub fn encode_fli_color64<W: Write + Seek>(
        prev: Option<&Raster>, next: &Raster, w: &mut W)
        -> FlicResult<usize> {
    match prev {
        Some(prev) => encode_fli_color64_delta(prev, next, w),
        None => encode_fli_color64_full(next, w),
    }
}

fn encode_fli_color64_full<W: Write + Seek>(
        next: &Raster, w: &mut W)
        -> FlicResult<usize> {
    if next.pal.len() % 3 != 0 || next.pal.len() > 3 * 256 {
        return Err(FlicError::BadInput);
    }

    let pos0 = try!(w.seek(SeekFrom::Current(0)));

    let count = 1;
    let nskip = 0;
    let ncopy = (next.pal.len() / 3) as u8;
    try!(w.write_u16::<LE>(count));
    try!(w.write_u8(nskip));
    try!(w.write_u8(ncopy));

    for i in 0..next.pal.len() {
        try!(w.write_u8(next.pal[i] / 4));
    }

    let pos1 = try!(w.seek(SeekFrom::Current(0)));
    Ok((pos1 - pos0) as usize)
}

fn encode_fli_color64_delta<W: Write + Seek>(
        prev: &Raster, next: &Raster, w: &mut W)
        -> FlicResult<usize> {
    if prev.pal.len() != next.pal.len()
            || prev.pal.len() % 3 != 0
            || next.pal.len() % 3 != 0 {
        return Err(FlicError::BadInput);
    }

    // Reserve space for count.
    let pos0 = try!(w.seek(SeekFrom::Current(0)));
    try!(w.write_u16::<LE>(0));

    let mut count = 0;

    for g in GroupByEq::new(prev.pal.chunks(3), next.pal.chunks(3))
            .set_prepend_same_run()
            .set_ignore_final_same_run() {
        match g {
            Group::Same(_, nskip) => {
                assert!(nskip <= ::std::u8::MAX as usize);
                try!(w.write_u8(nskip as u8));
            },
            Group::Diff(idx, ncopy) => {
                let start = 3 * idx;
                let end = start + 3 * ncopy;
                assert!(ncopy <= ::std::u8::MAX as usize + 1);
                try!(w.write_u8(ncopy as u8));

                for i in start..end {
                    try!(w.write_u8(next.pal[i] / 4));
                }
            },
        }

        count = count + 1;
    }

    // If odd number, pad it to be even.
    let mut pos1 = try!(w.seek(SeekFrom::Current(0)));
    if (pos1 - pos0) % 2 == 1 {
        try!(w.write_u8(0));
        pos1 = pos1 + 1;
    }

    try!(w.seek(SeekFrom::Start(pos0)));
    if count > 0 {
        assert!(count % 2 == 0);
        assert!(count / 2 <= ::std::u16::MAX as u32);
        try!(w.write_u16::<LE>((count / 2) as u16));
        try!(w.seek(SeekFrom::Start(pos1)));

        Ok((pos1 - pos0) as usize)
    } else {
        Ok(0)
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use ::{Raster,RasterMut};
    use super::*;

    #[test]
    fn test_decode_fli_color64() {
        let src = [
            0x02, 0x00, // count 2
            1, 2,       // skip 1, copy 2
            0x0A, 0x0B, 0x0C, 0x1A, 0x1B, 0x1C,
            3, 4,       // skip 3, copy 4
            0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F ];

        let expected = [
            0x00, 0x00, 0x00,
            4*0x0A, 4*0x0B, 4*0x0C, 4*0x1A, 4*0x1B, 4*0x1C,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            4*0x2A, 4*0x2B, 4*0x2C, 4*0x2D, 4*0x2E, 4*0x2F, 4*0x3A, 4*0x3B, 4*0x3C, 4*0x3D, 4*0x3E, 4*0x3F,
            0x00, 0x00, 0x00 ];

        const SCREEN_W: usize = 320;
        const SCREEN_H: usize = 200;
        let mut buf = [0; SCREEN_W * SCREEN_H];
        let mut pal = [0; 3 * 256];

        let res = decode_fli_color64(&src,
                &mut RasterMut::new(SCREEN_W, SCREEN_H, &mut buf, &mut pal));
        assert!(res.is_ok());
        assert_eq!(&pal[0..33], &expected[..]);
    }

    #[test]
    fn test_encode_fli_color64() {
        let src = [
            4*0x0A, 4*0x0B, 4*0x0C, 4*0x1A, 4*0x1B, 4*0x1C,
            4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00,
            4*0x2A, 4*0x2B, 4*0x2C, 4*0x3A, 4*0x3B, 4*0x3C, 4*0x3D, 4*0x3E, 4*0x3F,
            4*0x00, 4*0x00, 4*0x00 ];

        let expected = [
            0x02, 0x00, // count 2
            0, 2,       // skip 0, copy 2
            0x0A, 0x0B, 0x0C, 0x1A, 0x1B, 0x1C,
            3, 3,       // skip 3, copy 3
            0x2A, 0x2B, 0x2C, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
            0x00 ];     // even

        const SCREEN_W: usize = 320;
        const SCREEN_H: usize = 200;
        const NUM_COLS: usize = 256;
        let buf = [0; SCREEN_W * SCREEN_H];
        let pal1 = [0; 3 * NUM_COLS];
        let mut pal2 = [0; 3 * NUM_COLS];
        pal2[0..27].copy_from_slice(&src[..]);

        let mut enc: Cursor<Vec<u8>> = Cursor::new(Vec::new());

        let prev = Raster::new(SCREEN_W, SCREEN_H, &buf, &pal1);
        let next = Raster::new(SCREEN_W, SCREEN_H, &buf, &pal2);
        let res = encode_fli_color64(Some(&prev), &next, &mut enc);
        assert!(res.is_ok());
        assert_eq!(&enc.get_ref()[..], &expected[..]);
    }
}
<commit_msg>Increase test coverage for FLI_COLOR64.<commit_after>//! Codec for chunk type 11 = FLI_COLOR64.

use std::io::{Cursor,Read,Seek,SeekFrom,Write};
use byteorder::LittleEndian as LE;
use byteorder::{ReadBytesExt,WriteBytesExt};

use ::{FlicError,FlicResult,Raster,RasterMut};
use super::{Group,GroupByEq};

/// Magic for a FLI_COLOR64 chunk - 64-Level Color.
///
/// This chunk is identical to FLI_COLOR256 except that the values for
/// the red, green and blue components are in the range of 0-63
/// instead of 0-255.
pub const FLI_COLOR64: u16 = 11;

/// Decode a FLI_COLOR64 chunk.
pub fn decode_fli_color64(src: &[u8], dst: &mut RasterMut)
        -> FlicResult<()> {
    let mut r = Cursor::new(src);
    let mut idx0 = 0;

    let count = try!(r.read_u16::<LE>());
    for _ in 0..count {
        let nskip = try!(r.read_u8()) as usize;
        let ncopy = match try!(r.read_u8()) {
            0 => 256 as usize,
            n => n as usize,
        };

        let start = idx0 + 3 * nskip;
        let end = start + 3 * ncopy;
        if end > dst.pal.len() {
            return Err(FlicError::Corrupted);
        }

        try!(r.read_exact(&mut dst.pal[start..end]));
        for i in start..end {
            if dst.pal[i] > ::std::u8::MAX / 4 {
                return Err(FlicError::Corrupted);
            }

            dst.pal[i] = 4 * dst.pal[i];
        }

        idx0 = end;
    }

    Ok(())
}

/// Encode a FLI_COLOR64 chunk.
pub fn encode_fli_color64<W: Write + Seek>(
        prev: Option<&Raster>, next: &Raster, w: &mut W)
        -> FlicResult<usize> {
    match prev {
        Some(prev) => encode_fli_color64_delta(prev, next, w),
        None => encode_fli_color64_full(next, w),
    }
}

fn encode_fli_color64_full<W: Write + Seek>(
        next: &Raster, w: &mut W)
        -> FlicResult<usize> {
    if next.pal.len() % 3 != 0 || next.pal.len() > 3 * 256 {
        return Err(FlicError::BadInput);
    }

    let pos0 = try!(w.seek(SeekFrom::Current(0)));

    let count = 1;
    let nskip = 0;
    let ncopy = (next.pal.len() / 3) as u8;
    try!(w.write_u16::<LE>(count));
    try!(w.write_u8(nskip));
    try!(w.write_u8(ncopy));

    for i in 0..next.pal.len() {
        try!(w.write_u8(next.pal[i] / 4));
    }

    let pos1 = try!(w.seek(SeekFrom::Current(0)));
    Ok((pos1 - pos0) as usize)
}

fn encode_fli_color64_delta<W: Write + Seek>(
        prev: &Raster, next: &Raster, w: &mut W)
        -> FlicResult<usize> {
    if prev.pal.len() != next.pal.len()
            || prev.pal.len() % 3 != 0
            || next.pal.len() % 3 != 0 {
        return Err(FlicError::BadInput);
    }

    // Reserve space for count.
    let pos0 = try!(w.seek(SeekFrom::Current(0)));
    try!(w.write_u16::<LE>(0));

    let mut count = 0;

    for g in GroupByEq::new(prev.pal.chunks(3), next.pal.chunks(3))
            .set_prepend_same_run()
            .set_ignore_final_same_run() {
        match g {
            Group::Same(_, nskip) => {
                assert!(nskip <= ::std::u8::MAX as usize);
                try!(w.write_u8(nskip as u8));
            },
            Group::Diff(idx, ncopy) => {
                let start = 3 * idx;
                let end = start + 3 * ncopy;
                assert!(ncopy <= ::std::u8::MAX as usize + 1);
                try!(w.write_u8(ncopy as u8));

                for i in start..end {
                    try!(w.write_u8(next.pal[i] / 4));
                }
            },
        }

        count = count + 1;
    }

    // If odd number, pad it to be even.
    let mut pos1 = try!(w.seek(SeekFrom::Current(0)));
    if (pos1 - pos0) % 2 == 1 {
        try!(w.write_u8(0));
        pos1 = pos1 + 1;
    }

    try!(w.seek(SeekFrom::Start(pos0)));
    if count > 0 {
        assert!(count % 2 == 0);
        assert!(count / 2 <= ::std::u16::MAX as u32);
        try!(w.write_u16::<LE>((count / 2) as u16));
        try!(w.seek(SeekFrom::Start(pos1)));

        Ok((pos1 - pos0) as usize)
    } else {
        Ok(0)
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use ::{Raster,RasterMut};
    use super::*;

    #[test]
    fn test_decode_fli_color64() {
        let src = [
            0x02, 0x00, // count 2
            1, 2,       // skip 1, copy 2
            0x0A, 0x0B, 0x0C, 0x1A, 0x1B, 0x1C,
            3, 4,       // skip 3, copy 4
            0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F ];

        let expected = [
            0x00, 0x00, 0x00,
            4*0x0A, 4*0x0B, 4*0x0C, 4*0x1A, 4*0x1B, 4*0x1C,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            4*0x2A, 4*0x2B, 4*0x2C, 4*0x2D, 4*0x2E, 4*0x2F, 4*0x3A, 4*0x3B, 4*0x3C, 4*0x3D, 4*0x3E, 4*0x3F,
            0x00, 0x00, 0x00 ];

        const SCREEN_W: usize = 320;
        const SCREEN_H: usize = 200;
        let mut buf = [0; SCREEN_W * SCREEN_H];
        let mut pal = [0; 3 * 256];

        let res = decode_fli_color64(&src,
                &mut RasterMut::new(SCREEN_W, SCREEN_H, &mut buf, &mut pal));
        assert!(res.is_ok());
        assert_eq!(&pal[0..33], &expected[..]);
    }

    #[test]
    fn test_encode_fli_color64_delta() {
        let src = [
            4*0x0A, 4*0x0B, 4*0x0C, 4*0x1A, 4*0x1B, 4*0x1C,
            4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00, 4*0x00,
            4*0x2A, 4*0x2B, 4*0x2C, 4*0x3A, 4*0x3B, 4*0x3C, 4*0x3D, 4*0x3E, 4*0x3F,
            4*0x00, 4*0x00, 4*0x00 ];

        let expected = [
            0x02, 0x00, // count 2
            0, 2,       // skip 0, copy 2
            0x0A, 0x0B, 0x0C, 0x1A, 0x1B, 0x1C,
            3, 3,       // skip 3, copy 3
            0x2A, 0x2B, 0x2C, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
            0x00 ];     // even

        const SCREEN_W: usize = 320;
        const SCREEN_H: usize = 200;
        const NUM_COLS: usize = 256;
        let buf = [0; SCREEN_W * SCREEN_H];
        let pal1 = [0; 3 * NUM_COLS];
        let mut pal2 = [0; 3 * NUM_COLS];
        pal2[0..27].copy_from_slice(&src[..]);

        let mut enc: Cursor<Vec<u8>> = Cursor::new(Vec::new());

        let prev = Raster::new(SCREEN_W, SCREEN_H, &buf, &pal1);
        let next = Raster::new(SCREEN_W, SCREEN_H, &buf, &pal2);
        let res = encode_fli_color64(Some(&prev), &next, &mut enc);
        assert!(res.is_ok());
        assert_eq!(&enc.get_ref()[..], &expected[..]);
    }

    #[test]
    fn test_encode_fli_color64_full() {
        const SCREEN_W: usize = 320;
        const SCREEN_H: usize = 200;
        const NUM_COLS: usize = 256;

        let buf = [0; SCREEN_W * SCREEN_H];
        let mut pal = [0; 3 * NUM_COLS];
        let mut expected = [0; 4 + 3 * NUM_COLS];
        expected[0] = 0x01; // count 1, skip 0, copy 256

        for i in 0..NUM_COLS {
            let c = (i as u8) / 4;

            pal[3 * i + 0] = 4 * c;
            pal[3 * i + 1] = 4 * c;
            pal[3 * i + 2] = 4 * c;

            expected[4 + 3 * i + 0] = c;
            expected[4 + 3 * i + 1] = c;
            expected[4 + 3 * i + 2] = c;
        }

        let mut enc: Cursor<Vec<u8>> = Cursor::new(Vec::new());

        let next = Raster::new(SCREEN_W, SCREEN_H, &buf, &pal);
        let res = encode_fli_color64(None, &next, &mut enc);
        assert!(res.is_ok());
        assert_eq!(&enc.get_ref()[..], &expected[..]);
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route_recognizer";
extern crate conduit;

use std::collections::HashMap;
use router::{Router, Match};
use conduit::{Method, Handler};

pub struct RouteBuilder<E> {
    routers: HashMap<Method, Router<Box<Handler<E>>>>
}

macro_rules! method_map(
    ($method:ident => $variant:ty) => (
        pub fn $method<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                                -> &'a mut RouteBuilder<E>
        {
            self.map(conduit::$variant, pattern, handler)
        }
    )
)

impl<E> RouteBuilder<E> {
    pub fn new() -> RouteBuilder<E> {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str) -> Result<Match<&'a Box<Handler<E>>>, String> {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: 'static + Handler<E>>(&'a mut self,
                                        method: Method, pattern: &str, handler: H)
                                        -> &'a mut RouteBuilder<E>
    {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler<E>>);
        }
        self
    }

    pub fn get<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Head, pattern, handler)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;
    use conduit;
    use conduit::{Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel;

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { unimplemented!() }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str { unimplemented!() }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions { unimplemented!() }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions { unimplemented!() }
    }

    #[test]
    fn basic_test() {
        let mut router = RouteBuilder::new();
        router.get("/posts/:id", handler1);

        let m = router.recognize(&conduit::Get, "/posts/1").unwrap();
        let res = (*m.handler).call(&mut RequestSentinel).unwrap();

        assert_eq!(res.status, (200, "OK"));
    }

    fn handler1(_: &mut conduit::Request) -> Result<conduit::Response, ()> {
        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(vec!())
        })
    }
}
<commit_msg>Router is now a conduit handler<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route_recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::Any;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder<E> {
    routers: HashMap<Method, Router<Box<Handler<E>>>>
}

macro_rules! method_map(
    ($method:ident => $variant:ty) => (
        pub fn $method<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                                -> &'a mut RouteBuilder<E>
        {
            self.map(conduit::$variant, pattern, handler)
        }
    )
)

impl<E> RouteBuilder<E> {
    pub fn new() -> RouteBuilder<E> {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str) -> Result<Match<&'a Box<Handler<E>>>, String> {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: 'static + Handler<E>>(&'a mut self,
                                        method: Method, pattern: &str, handler: H)
                                        -> &'a mut RouteBuilder<E>
    {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler<E>>);
        }
        self
    }

    pub fn get<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: 'static + Handler<E>>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder<E>
    {
        self.map(conduit::Head, pattern, handler)
    }
}

impl<E> conduit::Handler<E> for RouteBuilder<E> {
    fn call(&self, request: &mut Request) -> Result<Response, E> {
        let m = {
            let method = request.method();
            let path = request.path();

            self.recognize(&method, path).unwrap()
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use std::any::{Any, AnyRefExt};
    use super::*;

    use router::Params;
    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: HashMap<&'static str, Box<Any>>
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn as_conduit_handler() {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", handler1);
        router.get("/posts/:id", handler1);

        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).unwrap();

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "1, Get".to_str());

        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).unwrap();

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "10, Post".to_str());
    }

    fn handler1(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let params = req.extensions().find(&"router.params")
            .and_then(|a| a.as_ref::<Params>()).expect("Missing params");

        let mut res = vec!();
        res.push(params["id"]);
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::collections::BTreeMap;

use quire::validate as V;
use quire::ast::Ast as A;
use quire::ast::Ast;
use quire::ast::Tag::{NonSpecific};
use quire::ast::ScalarKind::{Plain};

type PortNumValidator = V::Numeric;

#[derive(RustcDecodable, Clone, PartialEq, Eq, Copy)]
#[allow(non_camel_case_types)]
pub enum Pid1Mode {
    exec = 0,
    wait = 1,
    wait_all_children = 2,
}

#[derive(RustcDecodable, Debug, Clone, PartialEq, Eq, Copy)]
#[allow(non_camel_case_types)]
pub enum SuperviseMode {
    wait_all,
    stop_on_failure,
    restart,
}

#[derive(RustcDecodable, Debug, Clone, PartialEq, Eq, Copy)]
#[allow(non_camel_case_types)]
pub enum WriteMode {
    read_only,
    //transient_reflink_copy, // TODO(tailhook)
    transient_hard_link_copy,
}

#[derive(RustcDecodable, Clone, PartialEq, Eq)]
pub struct Network {
    pub ip: String,
    pub hostname: Option<String>,
    pub ports: BTreeMap<u16, u16>,
}

#[derive(RustcDecodable, Clone, PartialEq, Eq)]
pub struct CommandInfo {
    // Common for toplevel commands
    pub description: Option<String>,
    pub banner: Option<String>,
    pub banner_delay: Option<u32>,
    pub epilog: Option<String>,

    // Command
    pub network: Option<Network>, // Only for top-levels
    pub pid1mode: Pid1Mode,
    pub work_dir: Option<String>,
    pub container: String,
    pub accepts_arguments: Option<bool>,
    pub environ: BTreeMap<String, String>,
    pub inherit_environ: Vec<String>,
    pub write_mode: WriteMode,
    pub run: Vec<String>,
    pub user_id: u32,
    pub external_user_id: Option<u32>,
}

#[derive(RustcDecodable, Clone, PartialEq, Eq)]
pub struct SuperviseInfo {
    // Common
    pub description: Option<String>,
    pub banner: Option<String>,
    pub banner_delay: Option<u32>,
    pub epilog: Option<String>,

    // Supervise
    pub mode: SuperviseMode,
    pub kill_unresponsive_after: u32,
    pub children: BTreeMap<String, ChildCommand>,
}

#[derive(RustcDecodable, PartialEq, Eq, Clone)]
pub enum MainCommand {
    Command(CommandInfo),
    Supervise(SuperviseInfo),
}

impl MainCommand {
    pub fn description<'x>(&'x self) -> Option<&'x String> {
        match *self {
            MainCommand::Command(ref cmd) => cmd.description.as_ref(),
            MainCommand::Supervise(ref cmd) => cmd.description.as_ref(),
        }
    }
}

#[derive(RustcDecodable, PartialEq, Eq, Clone)]
pub enum ChildCommand {
    Command(CommandInfo),
    BridgeCommand(CommandInfo),
}

impl ChildCommand {
    pub fn get_container<'x>(&'x self) -> &String {
        match *self {
            ChildCommand::Command(ref info) => &info.container,
            ChildCommand::BridgeCommand(ref info) => &info.container,
        }
    }
}

fn shell_command(ast: Ast) -> Vec<Ast> {
    match ast {
        A::Scalar(pos, _, style, value) => {
            return vec!(
                A::Scalar(pos.clone(), NonSpecific, Plain,
                          "/bin/sh".to_string()),
                A::Scalar(pos.clone(), NonSpecific, Plain,
                          "-c".to_string()),
                A::Scalar(pos.clone(), NonSpecific, style,
                          value),
                A::Scalar(pos.clone(), NonSpecific, Plain,
                          "--".to_string()),
                );
        }
        _ => unreachable!(),
    }
}

fn run_fields<'a>(network: bool) -> Vec<(String, Box<V::Validator + 'a>)> {
    let mut res = vec!(
        ("pid1mode".to_string(), Box::new(V::Scalar {
            default: Some("wait".to_string()),
            .. Default::default()}) as Box<V::Validator>),
        ("work_dir".to_string(), Box::new(V::Scalar {
            optional: true,
            .. Default::default()}) as Box<V::Validator>),
        ("container".to_string(), Box::new(V::Scalar {
            optional: true,
            .. Default::default()}) as Box<V::Validator>),
        ("accepts_arguments".to_string(), Box::new(V::Scalar {
            optional: true,
            .. Default::default()}) as Box<V::Validator>),
        ("environ".to_string(), Box::new(V::Mapping {
            key_element: Box::new(V::Scalar {
                .. Default::default()}) as Box<V::Validator>,
            value_element: Box::new(V::Scalar {
                .. Default::default()}) as Box<V::Validator>,
            .. Default::default()}) as Box<V::Validator>),
        ("inherit_environ".to_string(), Box::new(V::Sequence {
            element: Box::new(V::Scalar {
                .. Default::default()}) as Box<V::Validator>,
            .. Default::default()}) as Box<V::Validator>),
        ("write_mode".to_string(), Box::new(V::Scalar {
            default: Some("read-only".to_string()),
            .. Default::default()}) as Box<V::Validator>),
        ("run".to_string(), Box::new(V::Sequence {
            from_scalar: Some(shell_command as fn(Ast) -> Vec<Ast>),
            element: Box::new(V::Scalar {
                .. Default::default()}) as Box<V::Validator>,
            .. Default::default()}) as Box<V::Validator>),
        ("user_id".to_string(), Box::new(V::Numeric {
            min: Some(0),
            max: Some(1 << 30),
            default: Some(0),
            .. Default::default()}) as Box<V::Validator>),
        ("external_user_id".to_string(), Box::new(V::Numeric {
            min: Some(0),
            max: Some(1 << 30),
            optional: true,
            .. Default::default()}) as Box<V::Validator>),
    );
    if network {
        res.push(
            ("network".to_string(), Box::new(V::Structure {
                optional: true,
                members: vec!(
                ("ip".to_string(), Box::new(V::Scalar {
                    optional: true,
                    .. Default::default()}) as Box<V::Validator>),
                ("hostname".to_string(), Box::new(V::Scalar {
                    optional: true,
                    .. Default::default()}) as Box<V::Validator>),
                ("ports".to_string(), Box::new(V::Mapping {
                    key_element: Box::new(V::Numeric {
                        default: None,
                        .. Default::default()}) as Box<V::Validator>,
                    value_element: Box::new(V::Numeric {
                        default: None,
                        .. Default::default()}) as Box<V::Validator>,
                    .. Default::default()}) as Box<V::Validator>),
                ),.. Default::default()}) as Box<V::Validator>),
        );
    }
    return res;
}

fn command_fields<'a>() -> Vec<(String, Box<V::Validator + 'a>)> {
    return vec!(
        ("description".to_string(), Box::new(V::Scalar {
            optional: true,
            .. Default::default()}) as Box<V::Validator>),
        ("banner".to_string(), Box::new(V::Scalar {
            optional: true,
            .. Default::default()}) as Box<V::Validator>),
        ("banner_delay".to_string(), Box::new(V::Numeric {
            optional: true,
            min: Some(0),
            .. Default::default()}) as Box<V::Validator>),
        ("epilog".to_string(), Box::new(V::Scalar {
            optional: true,
            .. Default::default()}) as Box<V::Validator>),
        );
}

fn subcommand_validator<'a>() -> Box<V::Validator + 'a> {
    return Box::new(V::Enum { options: vec!(
        ("Command".to_string(), Box::new(V::Structure {
            members: run_fields(true),
            .. Default::default()}) as Box<V::Validator>),
        ("BridgeCommand".to_string(), Box::new(V::Structure {
            members: run_fields(false),
            .. Default::default()}) as Box<V::Validator>),
    ), .. Default::default()}) as Box<V::Validator>;
}

pub fn command_validator<'a>() -> V::Enum<'a> {
    let mut command_members = vec!();
    command_members.extend(command_fields().into_iter());
    command_members.extend(run_fields(false).into_iter());

    let mut supervise_members = vec!(
        ("mode".to_string(), Box::new(V::Scalar {
            default: Some("stop-on-failure".to_string()),
            .. Default::default()}) as Box<V::Validator>),
        ("children".to_string(), Box::new(V::Mapping {
            key_element: Box::new(V::Scalar {
                ..Default::default()}) as Box<V::Validator>,
            value_element: subcommand_validator(),
            .. Default::default()}) as Box<V::Validator>),
        ("kill_unresponsive_after".to_string(), Box::new(V::Numeric {
            default: Some(2),
            min: Some(1),
            max: Some(86400),
            .. Default::default()}) as Box<V::Validator>),
        );
    supervise_members.extend(command_fields().into_iter());

    return V::Enum { options: vec!(
        ("Command".to_string(), Box::new(V::Structure {
            members: command_members,
            .. Default::default()}) as Box<V::Validator>),
        ("Supervise".to_string(), Box::new(V::Structure {
            members: supervise_members,
            .. Default::default()}) as Box<V::Validator>),
    ), .. Default::default()};
}

pub trait Networking {
    fn network<'x>(&'x self) -> Option<&'x Network>;
}

impl Networking for ChildCommand {
    fn network<'x>(&'x self) -> Option<&'x Network> {
        match self {
            &ChildCommand::Command(ref cmd) => cmd.network.as_ref(),
            &ChildCommand::BridgeCommand(_) => None,
        }
    }
}
<commit_msg>Fix command validator<commit_after>use std::default::Default;
use std::collections::BTreeMap;

use quire::validate as V;
use quire::ast::Ast as A;
use quire::ast::Ast;
use quire::ast::Tag::{NonSpecific};
use quire::ast::ScalarKind::{Plain};

type PortNumValidator = V::Numeric;

#[derive(RustcDecodable, Clone, PartialEq, Eq, Copy)]
#[allow(non_camel_case_types)]
pub enum Pid1Mode {
    exec = 0,
    wait = 1,
    wait_all_children = 2,
}

#[derive(RustcDecodable, Debug, Clone, PartialEq, Eq, Copy)]
#[allow(non_camel_case_types)]
pub enum SuperviseMode {
    wait_all,
    stop_on_failure,
    restart,
}

#[derive(RustcDecodable, Debug, Clone, PartialEq, Eq, Copy)]
#[allow(non_camel_case_types)]
pub enum WriteMode {
    read_only,
    //transient_reflink_copy, // TODO(tailhook)
    transient_hard_link_copy,
}

#[derive(RustcDecodable, Clone, PartialEq, Eq)]
pub struct Network {
    pub ip: String,
    pub hostname: Option<String>,
    pub ports: BTreeMap<u16, u16>,
}

#[derive(RustcDecodable, Clone, PartialEq, Eq)]
pub struct CommandInfo {
    // Common for toplevel commands
    pub description: Option<String>,
    pub banner: Option<String>,
    pub banner_delay: Option<u32>,
    pub epilog: Option<String>,

    // Command
    pub network: Option<Network>, // Only for top-levels
    pub pid1mode: Pid1Mode,
    pub work_dir: Option<String>,
    pub container: String,
    pub accepts_arguments: Option<bool>,
    pub environ: BTreeMap<String, String>,
    pub write_mode: WriteMode,
    pub run: Vec<String>,
    pub user_id: u32,
    pub external_user_id: Option<u32>,
}

#[derive(RustcDecodable, Clone, PartialEq, Eq)]
pub struct SuperviseInfo {
    // Common
    pub description: Option<String>,
    pub banner: Option<String>,
    pub banner_delay: Option<u32>,
    pub epilog: Option<String>,

    // Supervise
    pub mode: SuperviseMode,
    pub kill_unresponsive_after: u32,
    pub children: BTreeMap<String, ChildCommand>,
}

#[derive(RustcDecodable, PartialEq, Eq, Clone)]
pub enum MainCommand {
    Command(CommandInfo),
    Supervise(SuperviseInfo),
}

impl MainCommand {
    pub fn description<'x>(&'x self) -> Option<&'x String> {
        match *self {
            MainCommand::Command(ref cmd) => cmd.description.as_ref(),
            MainCommand::Supervise(ref cmd) => cmd.description.as_ref(),
        }
    }
}

#[derive(RustcDecodable, PartialEq, Eq, Clone)]
pub enum ChildCommand {
    Command(CommandInfo),
    BridgeCommand(CommandInfo),
}

impl ChildCommand {
    pub fn get_container<'x>(&'x self) -> &String {
        match *self {
            ChildCommand::Command(ref info) => &info.container,
            ChildCommand::BridgeCommand(ref info) => &info.container,
        }
    }
}

fn shell_command(ast: Ast) -> Vec<Ast> {
    match ast {
        A::Scalar(pos, _, style, value) => {
            return vec!(
                A::Scalar(pos.clone(), NonSpecific, Plain,
                          "/bin/sh".to_string()),
                A::Scalar(pos.clone(), NonSpecific, Plain,
                          "-c".to_string()),
                A::Scalar(pos.clone(), NonSpecific, style,
                          value),
                A::Scalar(pos.clone(), NonSpecific, Plain,
                          "--".to_string()),
                );
        }
        _ => unreachable!(),
    }
}

fn run_fields<'a>(cmd: V::Structure, network: bool) -> V::Structure {
    let mut cmd = cmd
        .member("pid1mode", V::Scalar::new().default("wait"))
        .member("work_dir", V::Scalar::new().optional())
        .member("container", V::Scalar::new())
        .member("accepts_arguments", V::Scalar::new().optional())
        .member("environ", V::Mapping::new(V::Scalar::new(), V::Scalar::new()))
        .member("write_mode", V::Scalar::new().default("read-only"))
        .member("run", V::Sequence::new(V::Scalar::new())
            .parser(shell_command as fn(Ast) -> Vec<Ast>))
        .member("user_id", V::Numeric::new().min(0).max(1 << 30).default(0))
        .member("external_user_id",
            V::Numeric::new().min(0).max(1 << 30).optional());
    if network {
        cmd = cmd
            .member("network", V::Structure::new().optional()
                .member("ip", V::Scalar::new().optional())
                .member("hostname", V::Scalar::new().optional())
                .member("ports", V::Mapping::new(
                    V::Numeric::new(),
                    V::Numeric::new())))
    }
    return cmd;
}

fn command_fields<'a>(cmd: V::Structure) -> V::Structure {
    cmd
    .member("description", V::Scalar::new().optional())
    .member("banner", V::Scalar::new().optional())
    .member("banner_delay", V::Numeric::new().optional().min(0))
    .member("epilog", V::Scalar::new().optional())
}

fn subcommand_validator<'a>() -> V::Enum<'a> {
    V::Enum::new()
    .option("Command",
        run_fields(command_fields(V::Structure::new()), true))
    .option("BridgeCommand",
        run_fields(command_fields(V::Structure::new()), false))
}

pub fn command_validator<'a>() -> V::Enum<'a> {
    let cmd = run_fields(command_fields(V::Structure::new()), false);
    let sup = command_fields(V::Structure::new());

    let sup = sup
        .member("mode", V::Scalar::new().default("stop-on-failure"))
        .member("children", V::Mapping::new(
            V::Scalar::new(),
            subcommand_validator()))
        .member("kill_unresponsive_after",
            V::Numeric::new().default(2).min(1).max(86400));

    return V::Enum::new()
        .option("Command", cmd)
        .option("Supervise", sup);
}

pub trait Networking {
    fn network<'x>(&'x self) -> Option<&'x Network>;
}

impl Networking for ChildCommand {
    fn network<'x>(&'x self) -> Option<&'x Network> {
        match self {
            &ChildCommand::Command(ref cmd) => cmd.network.as_ref(),
            &ChildCommand::BridgeCommand(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Index, RangeTo, RangeFrom, RangeFull};
use core::card::Card;
use core::deck::Deck;

extern crate rand;
use self::rand::{thread_rng, sample, Rng};

/// `FlatDeck` is a deck of cards that allows easy
/// indexing into the cards. It does not provide
/// contains methods.
#[derive(Debug)]
pub struct FlatDeck {
    /// Card storage.
    cards: Vec<Card>,
}

impl FlatDeck {
    /// How many cards are there in the deck ?
    pub fn len(&self) -> usize {
        self.cards.len()
    }
    /// Have all cards been dealt ?
    /// This probably won't be used as it's unlikely
    /// that someone will deal all 52 cards from a deck.
    pub fn is_empty(&self) -> bool {
        self.cards.is_empty()
    }

    /// Give a random sample of the cards still left in the deck
    pub fn sample(&self, n: usize) -> Vec<Card> {
        let mut rng = thread_rng();
        sample(&mut rng, &self.cards[..], n).iter().map(|c| *(*c)).collect()
    }

    /// Randomly shuffle the flat deck.
    /// This will ensure the there's no order to the deck.
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        rng.shuffle(&mut self.cards)
    }
}

impl Index<usize> for FlatDeck {
    type Output = Card;
    fn index(&self, index: usize) -> &Card {
        &self.cards[index]
    }
}
impl Index<RangeTo<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeTo<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFrom<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFrom<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFull> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFull) -> &[Card] {
        &self.cards[index]
    }
}

/// Trait that means a deck can be made into a `FlatDeck`
pub trait Flattenable {
    /// Consume a `Deck` and produce a deck suitable for random index.
    fn flatten(self) -> FlatDeck;
}

/// Allow creating a flat deck from a Deck
impl Flattenable for Deck {
    /// Flatten this deck, consuming it to produce a `FlatDeck` that's
    /// easier to get random access to.
    fn flatten(self) -> FlatDeck {
        FlatDeck { cards: self.into_iter().collect() }
    }
}

impl Into<FlatDeck> for Deck {
    fn into(self) -> FlatDeck {
        self.flatten()
    }
}
<commit_msg>Add on FlatDeck#deal<commit_after>use std::ops::{Index, RangeTo, RangeFrom, RangeFull};
use core::card::Card;
use core::deck::Deck;

extern crate rand;
use self::rand::{thread_rng, sample, Rng};

/// `FlatDeck` is a deck of cards that allows easy
/// indexing into the cards. It does not provide
/// contains methods.
#[derive(Debug)]
pub struct FlatDeck {
    /// Card storage.
    cards: Vec<Card>,
}

impl FlatDeck {
    /// How many cards are there in the deck ?
    pub fn len(&self) -> usize {
        self.cards.len()
    }
    /// Have all cards been dealt ?
    /// This probably won't be used as it's unlikely
    /// that someone will deal all 52 cards from a deck.
    pub fn is_empty(&self) -> bool {
        self.cards.is_empty()
    }

    /// Give a random sample of the cards still left in the deck
    pub fn sample(&self, n: usize) -> Vec<Card> {
        let mut rng = thread_rng();
        sample(&mut rng, &self.cards[..], n).iter().map(|c| *(*c)).collect()
    }

    /// Randomly shuffle the flat deck.
    /// This will ensure the there's no order to the deck.
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        rng.shuffle(&mut self.cards)
    }

    /// Deal a card if there is one there to deal.
    /// None if the deck is empty
    pub fn deal(&mut self) -> Option<Card> {
        self.cards.pop()
    }
}

impl Index<usize> for FlatDeck {
    type Output = Card;
    fn index(&self, index: usize) -> &Card {
        &self.cards[index]
    }
}
impl Index<RangeTo<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeTo<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFrom<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFrom<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFull> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFull) -> &[Card] {
        &self.cards[index]
    }
}

/// Trait that means a deck can be made into a `FlatDeck`
pub trait Flattenable {
    /// Consume a `Deck` and produce a deck suitable for random index.
    fn flatten(self) -> FlatDeck;
}

/// Allow creating a flat deck from a Deck
impl Flattenable for Deck {
    /// Flatten this deck, consuming it to produce a `FlatDeck` that's
    /// easier to get random access to.
    fn flatten(self) -> FlatDeck {
        FlatDeck { cards: self.into_iter().collect() }
    }
}

impl Into<FlatDeck> for Deck {
    fn into(self) -> FlatDeck {
        self.flatten()
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use toml;

macro_rules! toml_table {
    ($($key:expr => $value:expr),+) => {
        {
            let mut dep = BTreeMap::new();
            $(dep.insert(String::from($key), $value);)+
            toml::Value::Table(dep)
        }
    }
}

#[derive(Debug, Hash, PartialEq, Eq, Clone)]
enum DependencySource {
    Version(String),
    Git(String),
    Path(String),
}

/// A dependency handled by Cargo
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub struct Dependency {
    /// The name of the dependency (as it is set in its `Cargo.toml` and known to crates.io)
    pub name: String,
    optional: bool,
    source: DependencySource,
}

impl Default for Dependency {
    fn default() -> Dependency {
        Dependency {
            name: "".into(),
            optional: false,
            source: DependencySource::Version("0.1.0".into()),
        }
    }
}

impl Dependency {
    /// Create a new dependency with a name
    pub fn new(name: &str) -> Dependency {
        Dependency { name: name.into(), ..Dependency::default() }
    }

    /// Set dependency to a given version
    pub fn set_version(mut self, version: &str) -> Dependency {
        self.source = DependencySource::Version(version.into());
        self
    }

    /// Set dependency to a given repository
    pub fn set_git(mut self, repo: &str) -> Dependency {
        self.source = DependencySource::Git(repo.into());
        self
    }

    /// Set dependency to a given path
    pub fn set_path(mut self, path: &str) -> Dependency {
        self.source = DependencySource::Path(path.into());
        self
    }

    /// Set whether the dependency is optional
    pub fn set_optional(mut self, opt: bool) -> Dependency {
        self.optional = opt;
        self
    }

    /// Get version of dependency
    pub fn version(&self) -> Option<&str> {
        if let DependencySource::Version(ref version) = self.source {
            Some(version)
        } else {
            None
        }
    }

    /// Convert dependency to TOML
    ///
    /// Returns a tuple with the dependency's name and either the version as a String or the
    /// the path/git repository as a table. (If the dependency is set as `optional`, a tables is
    /// returned in any case.)
    pub fn to_toml(&self) -> (String, toml::Value) {
        let data: toml::Value = match (self.optional, self.source.clone()) {
            // Extra short when version flag only
            (false, DependencySource::Version(v)) => toml::Value::String(v),
            // Other cases are represented as tables
            (optional, source) => {
                let mut data = BTreeMap::new();

                match source {
                    DependencySource::Version(v) => {
                        data.insert("version".into(), toml::Value::String(v));
                    }
                    DependencySource::Git(v) => {
                        data.insert("git".into(), toml::Value::String(v));
                    }
                    DependencySource::Path(v) => {
                        data.insert("path".into(), toml::Value::String(v));
                    }
                }
                data.insert("optional".into(), toml::Value::Boolean(optional));

                toml::Value::Table(data)
            }
        };

        (self.name.clone(), data)
    }
}
<commit_msg>Remove unused macro<commit_after>use std::collections::BTreeMap;
use toml;

#[derive(Debug, Hash, PartialEq, Eq, Clone)]
enum DependencySource {
    Version(String),
    Git(String),
    Path(String),
}

/// A dependency handled by Cargo
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub struct Dependency {
    /// The name of the dependency (as it is set in its `Cargo.toml` and known to crates.io)
    pub name: String,
    optional: bool,
    source: DependencySource,
}

impl Default for Dependency {
    fn default() -> Dependency {
        Dependency {
            name: "".into(),
            optional: false,
            source: DependencySource::Version("0.1.0".into()),
        }
    }
}

impl Dependency {
    /// Create a new dependency with a name
    pub fn new(name: &str) -> Dependency {
        Dependency { name: name.into(), ..Dependency::default() }
    }

    /// Set dependency to a given version
    pub fn set_version(mut self, version: &str) -> Dependency {
        self.source = DependencySource::Version(version.into());
        self
    }

    /// Set dependency to a given repository
    pub fn set_git(mut self, repo: &str) -> Dependency {
        self.source = DependencySource::Git(repo.into());
        self
    }

    /// Set dependency to a given path
    pub fn set_path(mut self, path: &str) -> Dependency {
        self.source = DependencySource::Path(path.into());
        self
    }

    /// Set whether the dependency is optional
    pub fn set_optional(mut self, opt: bool) -> Dependency {
        self.optional = opt;
        self
    }

    /// Get version of dependency
    pub fn version(&self) -> Option<&str> {
        if let DependencySource::Version(ref version) = self.source {
            Some(version)
        } else {
            None
        }
    }

    /// Convert dependency to TOML
    ///
    /// Returns a tuple with the dependency's name and either the version as a String or the
    /// the path/git repository as a table. (If the dependency is set as `optional`, a tables is
    /// returned in any case.)
    pub fn to_toml(&self) -> (String, toml::Value) {
        let data: toml::Value = match (self.optional, self.source.clone()) {
            // Extra short when version flag only
            (false, DependencySource::Version(v)) => toml::Value::String(v),
            // Other cases are represented as tables
            (optional, source) => {
                let mut data = BTreeMap::new();

                match source {
                    DependencySource::Version(v) => {
                        data.insert("version".into(), toml::Value::String(v));
                    }
                    DependencySource::Git(v) => {
                        data.insert("git".into(), toml::Value::String(v));
                    }
                    DependencySource::Path(v) => {
                        data.insert("path".into(), toml::Value::String(v));
                    }
                }
                data.insert("optional".into(), toml::Value::Boolean(optional));

                toml::Value::Table(data)
            }
        };

        (self.name.clone(), data)
    }
}
<|endoftext|>