<commit_before>use async::bufreader::AsyncBufReader;
use async::bufwriter::AsyncBufWriter;
use transport::{hton, ntoh, unencrypted_read_packet};

use std::{fmt, io, str};
use std::io::{Read, Write};
use futures::{Future, done};
use rand::Rng;
use tokio_core::io::{flush, read_until, write_all};

use ::SSH_MSG_KEYINIT;

pub enum HandshakeError {
    IoError(io::Error),
    InvalidVersionExchange,
    InvalidAlgorithmNegotiation
}

impl From<io::Error> for HandshakeError {
    fn from(e: io::Error) -> HandshakeError {
        HandshakeError::IoError(e)
    }
}

#[derive(Debug, Default)]
pub struct AlgorithmNegotiation {
    pub kex_algorithms: Vec<String>,
    pub server_host_key_algorithms: Vec<String>,
    pub encryption_algorithms_client_to_server: Vec<String>,
    pub encryption_algorithms_server_to_client: Vec<String>,
    pub mac_algorithms_client_to_server: Vec<String>,
    pub mac_algorithms_server_to_client: Vec<String>,
    pub compression_algorithms_client_to_server: Vec<String>,
    pub compression_algorithms_server_to_client: Vec<String>,
    pub languages_client_to_server: Vec<String>,
    pub languages_server_to_client: Vec<String>,
    pub first_kex_packet_follows: bool
}

pub struct AlgorithmNegotiationParser<'r> {
    buf: &'r [u8],
    pos: usize
}

impl <'r> AlgorithmNegotiationParser<'r> {
    fn new<'a>(buf: &'a [u8]) -> AlgorithmNegotiationParser<'a> {
        AlgorithmNegotiationParser {
            buf: buf,
            pos: 0
        }
    }

    fn parse_name_list(&mut self) -> Result<Vec<String>, HandshakeError> {
        if self.pos + 4 > self.buf.len() {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        let list_len = ntoh(&self.buf[self.pos .. self.pos + 4]) as usize;
        self.pos += 4;

        if self.pos + list_len > self.buf.len() {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        let list: Result<Vec<String>, HandshakeError> = self.buf[self.pos .. self.pos + list_len]
            .split(|&c| c == b',')
            .map(|slice|
                 match str::from_utf8(slice) {
                     Ok(s) => Ok(s.to_owned()),
                     Err(_) => Err(HandshakeError::InvalidAlgorithmNegotiation)
                 }
            ).collect();
        self.pos += list_len;

        list
    }

    fn parse(&mut self) -> Result<AlgorithmNegotiation, HandshakeError> {
        let mut data: AlgorithmNegotiation = Default::default();

        if self.buf[0] != SSH_MSG_KEYINIT {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        self.pos = 17;

        data.kex_algorithms = try!(self.parse_name_list());
        data.server_host_key_algorithms = try!(self.parse_name_list());
        data.encryption_algorithms_client_to_server = try!(self.parse_name_list());
        data.encryption_algorithms_server_to_client = try!(self.parse_name_list());
        data.mac_algorithms_client_to_server = try!(self.parse_name_list());
        data.mac_algorithms_server_to_client = try!(self.parse_name_list());
        data.compression_algorithms_client_to_server = try!(self.parse_name_list());
        data.compression_algorithms_server_to_client = try!(self.parse_name_list());
        data.languages_client_to_server = try!(self.parse_name_list());
        data.languages_server_to_client = try!(self.parse_name_list());

        if self.pos != self.buf.len() - 5 {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        data.first_kex_packet_follows =
            match self.buf[self.pos] {
                0 => false,
                1 => true,
                _ => return Err(HandshakeError::InvalidAlgorithmNegotiation)
            };

        Ok(data)
    }
}

fn write_named_list<W: Write, S: AsRef<[u8]>>(writer: &mut W, list: &[S]) -> io::Result<()> {
    let len = if list.len() == 0 {
        0
    } else {
        list.iter().map(|s| s.as_ref().len()).sum::<usize>() + list.len() - 1
    };

    if len > 0xffffffff {
        return Err(io::Error::new(io::ErrorKind::InvalidData, "named_list too long"));
    }

    let mut header = [0u8; 4];
    header[0] = (len >> 24) as u8;
    header[1] = (len >> 16) as u8;
    header[2] = (len >> 8) as u8;
    header[3] = len as u8;

    try!(writer.write(&header));
    let mut first = true;

    for name in list {
        if first {
            first = false;
        } else {
            try!(writer.write(b","));
        }

        try!(writer.write(name.as_ref()));
    }

    Ok(())
}

impl AlgorithmNegotiation {
    pub fn build_message(&self, rng: &mut Rng) -> Result<Vec<u8>, HandshakeError> {
        let mut payload = Vec::new();
        try!(payload.write(&[SSH_MSG_KEYINIT]));
        let mut cookie = [0u8; 16];
        rng.fill_bytes(&mut cookie);
        try!(payload.write(&cookie));
        try!(write_named_list(&mut payload, &self.kex_algorithms));
        try!(write_named_list(&mut payload, &self.server_host_key_algorithms));
        try!(write_named_list(&mut payload, &self.encryption_algorithms_client_to_server));
        try!(write_named_list(&mut payload, &self.encryption_algorithms_server_to_client));
        try!(write_named_list(&mut payload, &self.mac_algorithms_client_to_server));
        try!(write_named_list(&mut payload, &self.mac_algorithms_server_to_client));
        try!(write_named_list(&mut payload, &self.compression_algorithms_client_to_server));
        try!(write_named_list(&mut payload, &self.compression_algorithms_server_to_client));
        try!(write_named_list(&mut payload, &self.languages_client_to_server));
        try!(write_named_list(&mut payload, &self.languages_server_to_client));
        let flag: u8 = if self.first_kex_packet_follows { 1 } else { 0 };
        try!(payload.write(&[flag]));
        try!(payload.write(&[0u8; 4]));

        let mut buf = Vec::new();
        let payload_len = payload.len();
        let pad_len = 8 - ((payload_len + 1) % 8);
        let pkt_len = payload_len + pad_len - 1;
        let mut padding = vec![0u8; pad_len];
        rng.fill_bytes(&mut padding);

        try!(buf.write(&hton(pkt_len as u32)));
        try!(buf.write(&[pad_len as u8]));
        try!(buf.write(&payload));
        try!(buf.write(&padding));

        Ok(buf)
    }
}

impl fmt::Display for HandshakeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HandshakeError::IoError(ref e) => e.fmt(f),
            HandshakeError::InvalidVersionExchange => write!(f, "InvalidVersionExchange"),
            HandshakeError::InvalidAlgorithmNegotiation => write!(f, "InvalidAlgorithmNegotiation")
        }
    }
}

pub fn version_exchange<R, W>(reader: AsyncBufReader<R>, writer: AsyncBufWriter<W>, version_string: &str, comment: &str)
        -> Box<Future<Item=(AsyncBufReader<R>, AsyncBufWriter<W>, Vec<u8>), Error=HandshakeError>>
    where R: Read + Send + 'static, W: Write + Send + 'static
{
    let mut buf = Vec::with_capacity(256);
    write!(buf, "SSH-2.0-{} {}\r\n", version_string, comment).unwrap();
    if buf.len() > 255 {
        panic!("version string and comment too long");
    }

    let w = write_all(writer, buf).and_then(|(writer, _)| {
        flush(writer)
    }).map_err(|e| e.into());

    let r = read_until(reader, b'\n', Vec::with_capacity(256)).map_err(|e| e.into()).and_then(|(reader, buf)| {
        if buf.starts_with(b"SSH-2.0-") && buf.ends_with(b"\r\n") {
            Ok((reader, buf[8 .. buf.len()-2].to_vec()))
        } else {
            Err(HandshakeError::InvalidVersionExchange)
        }
    });

    w.join(r).map(|(writer, (reader, version))| (reader, writer, version)).boxed()
}

pub fn algorithm_negotiation<R, W>(reader: AsyncBufReader<R>, writer: AsyncBufWriter<W>, supported_algorithms: &AlgorithmNegotiation, rng: &mut Rng)
        -> Box<Future<Item=(AsyncBufReader<R>, AsyncBufWriter<W>, AlgorithmNegotiation), Error=HandshakeError>>
    where R: Read + Send + 'static, W: Write + Send + 'static
{
    let w = done(supported_algorithms.build_message(rng)).and_then(|message| {
        write_all(writer, message).and_then(|(writer, _)| {
            flush(writer)
        }).map_err(|e| e.into())
    });

    let r = unencrypted_read_packet(reader).map_err(|e| e.into()).and_then(|(reader, buf)| {
        let slice = buf.as_ref();
        let mut parser = AlgorithmNegotiationParser::new(slice);
        parser.parse().map(|neg| (reader, neg))
    });

    w.join(r).map(|(writer, (reader, packet))| (reader, writer, packet)).boxed()
}
<commit_msg>Fix padding length computation<commit_after>use async::bufreader::AsyncBufReader;
use async::bufwriter::AsyncBufWriter;
use transport::{hton, ntoh, unencrypted_read_packet};

use std::{fmt, io, str};
use std::io::{Read, Write};
use futures::{Future, done};
use rand::Rng;
use tokio_core::io::{flush, read_until, write_all};

use ::SSH_MSG_KEYINIT;

pub enum HandshakeError {
    IoError(io::Error),
    InvalidVersionExchange,
    InvalidAlgorithmNegotiation
}

impl From<io::Error> for HandshakeError {
    fn from(e: io::Error) -> HandshakeError {
        HandshakeError::IoError(e)
    }
}

#[derive(Debug, Default)]
pub struct AlgorithmNegotiation {
    pub kex_algorithms: Vec<String>,
    pub server_host_key_algorithms: Vec<String>,
    pub encryption_algorithms_client_to_server: Vec<String>,
    pub encryption_algorithms_server_to_client: Vec<String>,
    pub mac_algorithms_client_to_server: Vec<String>,
    pub mac_algorithms_server_to_client: Vec<String>,
    pub compression_algorithms_client_to_server: Vec<String>,
    pub compression_algorithms_server_to_client: Vec<String>,
    pub languages_client_to_server: Vec<String>,
    pub languages_server_to_client: Vec<String>,
    pub first_kex_packet_follows: bool
}

pub struct AlgorithmNegotiationParser<'r> {
    buf: &'r [u8],
    pos: usize
}

impl <'r> AlgorithmNegotiationParser<'r> {
    fn new<'a>(buf: &'a [u8]) -> AlgorithmNegotiationParser<'a> {
        AlgorithmNegotiationParser {
            buf: buf,
            pos: 0
        }
    }

    fn parse_name_list(&mut self) -> Result<Vec<String>, HandshakeError> {
        if self.pos + 4 > self.buf.len() {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        let list_len = ntoh(&self.buf[self.pos .. self.pos + 4]) as usize;
        self.pos += 4;

        if self.pos + list_len > self.buf.len() {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        let list: Result<Vec<String>, HandshakeError> = self.buf[self.pos .. self.pos + list_len]
            .split(|&c| c == b',')
            .map(|slice|
                 match str::from_utf8(slice) {
                     Ok(s) => Ok(s.to_owned()),
                     Err(_) => Err(HandshakeError::InvalidAlgorithmNegotiation)
                 }
            ).collect();
        self.pos += list_len;

        list
    }

    fn parse(&mut self) -> Result<AlgorithmNegotiation, HandshakeError> {
        let mut data: AlgorithmNegotiation = Default::default();

        if self.buf[0] != SSH_MSG_KEYINIT {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        self.pos = 17;

        data.kex_algorithms = try!(self.parse_name_list());
        data.server_host_key_algorithms = try!(self.parse_name_list());
        data.encryption_algorithms_client_to_server = try!(self.parse_name_list());
        data.encryption_algorithms_server_to_client = try!(self.parse_name_list());
        data.mac_algorithms_client_to_server = try!(self.parse_name_list());
        data.mac_algorithms_server_to_client = try!(self.parse_name_list());
        data.compression_algorithms_client_to_server = try!(self.parse_name_list());
        data.compression_algorithms_server_to_client = try!(self.parse_name_list());
        data.languages_client_to_server = try!(self.parse_name_list());
        data.languages_server_to_client = try!(self.parse_name_list());

        if self.pos != self.buf.len() - 5 {
            return Err(HandshakeError::InvalidAlgorithmNegotiation);
        }

        data.first_kex_packet_follows =
            match self.buf[self.pos] {
                0 => false,
                1 => true,
                _ => return Err(HandshakeError::InvalidAlgorithmNegotiation)
            };

        Ok(data)
    }
}

fn write_named_list<W: Write, S: AsRef<[u8]>>(writer: &mut W, list: &[S]) -> io::Result<()> {
    let len = if list.len() == 0 {
        0
    } else {
        list.iter().map(|s| s.as_ref().len()).sum::<usize>() + list.len() - 1
    };

    if len > 0xffffffff {
        return Err(io::Error::new(io::ErrorKind::InvalidData, "named_list too long"));
    }

    let mut header = [0u8; 4];
    header[0] = (len >> 24) as u8;
    header[1] = (len >> 16) as u8;
    header[2] = (len >> 8) as u8;
    header[3] = len as u8;

    try!(writer.write(&header));
    let mut first = true;

    for name in list {
        if first {
            first = false;
        } else {
            try!(writer.write(b","));
        }

        try!(writer.write(name.as_ref()));
    }

    Ok(())
}

impl AlgorithmNegotiation {
    pub fn build_message(&self, rng: &mut Rng) -> Result<Vec<u8>, HandshakeError> {
        let mut payload = Vec::new();
        try!(payload.write(&[SSH_MSG_KEYINIT]));
        let mut cookie = [0u8; 16];
        rng.fill_bytes(&mut cookie);
        try!(payload.write(&cookie));
        try!(write_named_list(&mut payload, &self.kex_algorithms));
        try!(write_named_list(&mut payload, &self.server_host_key_algorithms));
        try!(write_named_list(&mut payload, &self.encryption_algorithms_client_to_server));
        try!(write_named_list(&mut payload, &self.encryption_algorithms_server_to_client));
        try!(write_named_list(&mut payload, &self.mac_algorithms_client_to_server));
        try!(write_named_list(&mut payload, &self.mac_algorithms_server_to_client));
        try!(write_named_list(&mut payload, &self.compression_algorithms_client_to_server));
        try!(write_named_list(&mut payload, &self.compression_algorithms_server_to_client));
        try!(write_named_list(&mut payload, &self.languages_client_to_server));
        try!(write_named_list(&mut payload, &self.languages_server_to_client));
        let flag: u8 = if self.first_kex_packet_follows { 1 } else { 0 };
        try!(payload.write(&[flag]));
        try!(payload.write(&[0u8; 4]));

        let mut buf = Vec::new();
        let payload_len = payload.len();
        let pad_len = 8 - ((payload_len + 5) % 8);
        let pkt_len = payload_len + pad_len + 1;
        let mut padding = vec![0u8; pad_len];
        rng.fill_bytes(&mut padding);

        try!(buf.write(&hton(pkt_len as u32)));
        try!(buf.write(&[pad_len as u8]));
        try!(buf.write(&payload));
        try!(buf.write(&padding));

        Ok(buf)
    }
}

impl fmt::Display for HandshakeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HandshakeError::IoError(ref e) => e.fmt(f),
            HandshakeError::InvalidVersionExchange => write!(f, "InvalidVersionExchange"),
            HandshakeError::InvalidAlgorithmNegotiation => write!(f, "InvalidAlgorithmNegotiation")
        }
    }
}

pub fn version_exchange<R, W>(reader: AsyncBufReader<R>, writer: AsyncBufWriter<W>, version_string: &str, comment: &str)
        -> Box<Future<Item=(AsyncBufReader<R>, AsyncBufWriter<W>, Vec<u8>), Error=HandshakeError>>
    where R: Read + Send + 'static, W: Write + Send + 'static
{
    let mut buf = Vec::with_capacity(256);
    write!(buf, "SSH-2.0-{} {}\r\n", version_string, comment).unwrap();
    if buf.len() > 255 {
        panic!("version string and comment too long");
    }

    let w = write_all(writer, buf).and_then(|(writer, _)| {
        flush(writer)
    }).map_err(|e| e.into());

    let r = read_until(reader, b'\n', Vec::with_capacity(256)).map_err(|e| e.into()).and_then(|(reader, buf)| {
        if buf.starts_with(b"SSH-2.0-") && buf.ends_with(b"\r\n") {
            Ok((reader, buf[8 .. buf.len()-2].to_vec()))
        } else {
            Err(HandshakeError::InvalidVersionExchange)
        }
    });

    w.join(r).map(|(writer, (reader, version))| (reader, writer, version)).boxed()
}

pub fn algorithm_negotiation<R, W>(reader: AsyncBufReader<R>, writer: AsyncBufWriter<W>, supported_algorithms: &AlgorithmNegotiation, rng: &mut Rng)
        -> Box<Future<Item=(AsyncBufReader<R>, AsyncBufWriter<W>, AlgorithmNegotiation), Error=HandshakeError>>
    where R: Read + Send + 'static, W: Write + Send + 'static
{
    let w = done(supported_algorithms.build_message(rng)).and_then(|message| {
        write_all(writer, message).and_then(|(writer, _)| {
            flush(writer)
        }).map_err(|e| e.into())
    });

    let r = unencrypted_read_packet(reader).map_err(|e| e.into()).and_then(|(reader, buf)| {
        let slice = buf.as_ref();
        let mut parser = AlgorithmNegotiationParser::new(slice);
        parser.parse().map(|neg| (reader, neg))
    });

    w.join(r).map(|(writer, (reader, packet))| (reader, writer, packet)).boxed()
}
<|endoftext|>


<commit_before>use std::io::{self, BufRead, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::{Arc, RwLock};
use std::thread;

use chainerror::*;
use serde_json::{from_slice, from_value, to_string};

use varlink::{
    Call, Connection, ErrorKind, GetInterfaceDescriptionArgs, Reply, Request, VarlinkStream,
};
use varlink_stdinterfaces::org_varlink_resolver::{VarlinkClient, VarlinkClientInterface};

#[cfg(unix)]
use crate::watchclose_epoll::WatchClose;
#[cfg(windows)]
use crate::watchclose_windows::WatchClose;
use crate::Result;

pub fn handle<R, W>(resolver: &str, client_reader_o: R, mut client_writer: W) -> Result<bool>
where
    R: Read + AsRawFd + Send + 'static,
    W: Write + AsRawFd + Send + 'static,
{
    let conn = Connection::new(resolver)
        .map_err(mstrerr!("Failed to connect to resolver '{}'", resolver))?;

    let mut client_reader = unsafe {
        ::std::io::BufReader::new(::std::fs::File::from_raw_fd(client_reader_o.as_raw_fd()))
    };

    let mut resolver = VarlinkClient::new(conn);

    let mut upgraded = false;
    let mut last_iface = String::new();
    let mut last_service_stream: Option<VarlinkStream> = None;
    let mut address = String::new();

    loop {
        if !upgraded {
            let mut buf = Vec::new();
            match client_reader.read_until(b'\0', &mut buf) {
                Ok(0) => break,
                Err(_e) => break,
                _ => {}
            }

            // pop the last zero byte
            buf.pop();

            let mut req: Request = from_slice(&buf).map_err(mstrerr!("Error from slice"))?;

            if req.method == "org.varlink.service.GetInfo" {
                req.method = "org.varlink.resolver.GetInfo".into();
            }

            let n: usize = match req.method.rfind('.') {
                None => {
                    let method: String = String::from(req.method.as_ref());
                    let mut call = Call::new(&mut client_writer, &req);
                    call.reply_interface_not_found(Some(method))?;
                    return Ok(false);
                }
                Some(x) => x,
            };

            let iface = {
                if req.method == "org.varlink.service.GetInterfaceDescription" {
                    let val = req.parameters.clone().unwrap_or_default();
                    let args: GetInterfaceDescriptionArgs = from_value(val)?;
                    args.interface.into()
                } else {
                    String::from(&req.method[..n])
                }
            };

            if iface != last_iface {
                if iface.eq("org.varlink.resolver") {
                    address = String::from("unix:/run/org.varlink.resolver");
                } else {
                    address = match resolver.resolve(iface.clone()).call() {
                        Ok(r) => r.address,
                        _ => {
                            let mut call = Call::new(&mut client_writer, &req);
                            call.reply_interface_not_found(Some(iface))?;
                            return Ok(false);
                        }
                    };
                }
                last_iface = iface.clone();
            }

            let mut stream = match VarlinkStream::connect(&address) {
                Ok((a, _)) => a,
                _ => {
                    let mut call = Call::new(&mut client_writer, &req);
                    call.reply_interface_not_found(Some(iface))?;
                    return Ok(false);
                }
            };

            let (_, mut service_writer) = stream.split()?;
            let service_reader = WatchClose::new_read(&stream, &client_writer)?;
            let mut service_bufreader = ::std::io::BufReader::new(service_reader);

            last_service_stream = Some(stream);

            {
                let b = to_string(&req)? + "\0";

                service_writer.write_all(b.as_bytes())?;
                service_writer.flush()?;
            }

            if req.oneway.unwrap_or(false) {
                continue;
            }

            upgraded = req.upgrade.unwrap_or(false);

            loop {
                let mut buf = Vec::new();

                if service_bufreader.read_until(0, &mut buf)? == 0 {
                    break;
                }
                if buf.is_empty() {
                    return Err(strerr!("Connection Closed").into());
                }

                client_writer.write_all(&buf)?;
                client_writer.flush()?;

                buf.pop();

                let reply: Reply = from_slice(&buf)?;

                if upgraded || (!reply.continues.unwrap_or(false)) {
                    break;
                }
            }
        } else if let Some(ref mut service_stream) = last_service_stream {
            // Should copy back and forth, until someone disconnects.
            let (_, service_writer) = service_stream.split()?;
            let service_reader = WatchClose::new_read(service_stream, &client_writer)?;
            let client_reader = WatchClose::new_read(&client_reader_o, service_stream)?;

            use std::sync::mpsc::channel;
            let (tx_end, rx_end) = channel();

            // Should copy back and forth, until someone disconnects.
            {
                let copy1 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut client_reader = client_reader;
                    let mut service_writer = service_writer;

                    move || {
                        let r = copy(&mut client_reader, &mut service_writer);
                        tx_end.send(1).expect("channel should be open");
                        r
                    }
                });

                let copy2 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut service_reader = service_reader;

                    move || {
                        let r = copy(&mut service_reader, &mut client_writer);
                        tx_end.send(2).expect("channel should be open");
                        r
                    }
                });

                let end_tid = rx_end.recv()?;

                match end_tid {
                    1 => {
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = service_stream.shutdown();
                        unsafe { libc::close(service_stream.as_raw_fd()) };
                        r1?;

                        let _ = rx_end.recv()?;
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r2?;
                    }

                    2 => {
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = service_stream.shutdown();
                        unsafe { libc::close(service_stream.as_raw_fd()) };
                        r2?;

                        let _ = rx_end.recv()?;
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r1?;
                    }
                    _ => panic!("Unknown"),
                };
            }
/*
            {
                let copy1 = thread::spawn({
                    let mut client_reader = client_reader;
                    let mut service_writer = service_writer;

                    move || {
                        let r = copy(&mut client_reader, &mut service_writer);
                        eprintln!("copy1 end");
                        r
                    }
                });
                let copy2 = thread::spawn({
                    let mut service_reader = service_reader;

                    move || {
                        let r = copy(&mut service_reader, &mut client_writer);
                        eprintln!("copy2 end");
                        r
                    }
                });
                let r = copy2.join();
                r.unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::ConnectionAborted)))?;
                let r = copy1.join();
                r.unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::ConnectionAborted)))?;
            }
            */
            return Ok(true);
        }
         else {
            unreachable!();
        }

    }
    Ok(upgraded)
}

pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where
    R: Read,
    W: Write,
{
    use std::io::ErrorKind;
    use std::mem;

    let mut buf = unsafe {
        let mut buf: [u8; 8192] = mem::uninitialized();
        //reader.initializer().initialize(&mut buf);
        std::ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len());
        buf
    };

    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        writer.flush()?;
        written += len as u64;
    }
}

pub fn handle_connect<R, W>(
    connection: Arc<RwLock<Connection>>,
    client_reader_o: R,
    mut client_writer: W,
) -> Result<bool>
where
    R: Read + AsRawFd + Send + 'static,
    W: Write + AsRawFd + Send + 'static,
{
    let mut upgraded = false;

    let mut conn = connection.write().unwrap();

    if conn.stream.is_none() {
        return Err(varlink::context!(ErrorKind::ConnectionBusy).into());
    }

    let mut stream = conn.stream.take().unwrap();
    let mut service_writer = unsafe { ::std::fs::File::from_raw_fd(stream.as_raw_fd()) };

    let mut service_reader =
        ::std::io::BufReader::new(WatchClose::new_read(&stream, &client_writer)?);

    let mut client_reader =
        ::std::io::BufReader::new(WatchClose::new_read(&client_reader_o, &stream)?);

    loop {
        if !upgraded {
            let mut buf = Vec::new();
            // FIXME: check if service_writer was closed, while reading
            match client_reader.read_until(b'\0', &mut buf) {
                Ok(0) => break,
                Err(_e) => break,
                _ => {}
            }

            // pop the last zero byte
            buf.pop();

            let req: Request = from_slice(&buf)?;

            {
                buf.push(0);
                // FIXME: check if client_reader was closed, while writing
                service_writer.write_all(&buf)?;
                service_writer.flush()?;
            }

            if req.oneway.unwrap_or(false) {
                continue;
            }

            upgraded = req.upgrade.unwrap_or(false);

            loop {
                let mut buf = Vec::new();

                if service_reader.read_until(0, &mut buf)? == 0 {
                    break;
                }
                if buf.is_empty() {
                    return Err(strerr!("Connection Closed!").into());
                }

                client_writer.write_all(&buf)?;
                client_writer.flush()?;

                buf.pop();

                let reply: Reply = from_slice(&buf)?;

                if upgraded || !reply.continues.unwrap_or(false) {
                    break;
                }
            }
        } else {
            use std::sync::mpsc::channel;
            let (tx_end, rx_end) = channel();

            // Should copy back and forth, until someone disconnects.
            {
                let copy1 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut client_reader = WatchClose::new_read(&client_reader_o, &stream)?;

                    move || {
                        let r = copy(&mut client_reader, &mut service_writer);
                        tx_end.send(1).expect("channel should be open");
                        r
                    }
                });

                let copy2 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut service_reader = WatchClose::new_read(&stream, &client_writer)?;

                    move || {
                        let r = copy(&mut service_reader, &mut client_writer);
                        tx_end.send(2).expect("channel should be open");
                        r
                    }
                });

                let end_tid = rx_end.recv()?;

                match end_tid {
                    1 => {
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = stream.shutdown();
                        unsafe { libc::close(stream.as_raw_fd()) };
                        r1?;

                        let _ = rx_end.recv()?;
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r2?;
                    }

                    2 => {
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = stream.shutdown();
                        unsafe { libc::close(stream.as_raw_fd()) };
                        r2?;

                        let _ = rx_end.recv()?;
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r1?;
                    }
                    _ => panic!("Unknown"),
                };
            }
            return Ok(true);
        }
    }
    Ok(upgraded)
}
<commit_msg>remove old comments and unused code fragments<commit_after>use std::io::{self, BufRead, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::{Arc, RwLock};
use std::thread;

use chainerror::*;
use serde_json::{from_slice, from_value, to_string};

use varlink::{
    Call, Connection, ErrorKind, GetInterfaceDescriptionArgs, Reply, Request, VarlinkStream,
};
use varlink_stdinterfaces::org_varlink_resolver::{VarlinkClient, VarlinkClientInterface};

#[cfg(unix)]
use crate::watchclose_epoll::WatchClose;
#[cfg(windows)]
use crate::watchclose_windows::WatchClose;
use crate::Result;

pub fn handle<R, W>(resolver: &str, client_reader_o: R, mut client_writer: W) -> Result<bool>
where
    R: Read + AsRawFd + Send + 'static,
    W: Write + AsRawFd + Send + 'static,
{
    let conn = Connection::new(resolver)
        .map_err(mstrerr!("Failed to connect to resolver '{}'", resolver))?;

    let mut client_reader = unsafe {
        ::std::io::BufReader::new(::std::fs::File::from_raw_fd(client_reader_o.as_raw_fd()))
    };

    let mut resolver = VarlinkClient::new(conn);

    let mut upgraded = false;
    let mut last_iface = String::new();
    let mut last_service_stream: Option<VarlinkStream> = None;
    let mut address = String::new();

    loop {
        if !upgraded {
            let mut buf = Vec::new();
            match client_reader.read_until(b'\0', &mut buf) {
                Ok(0) => break,
                Err(_e) => break,
                _ => {}
            }

            // pop the last zero byte
            buf.pop();

            let mut req: Request = from_slice(&buf).map_err(mstrerr!("Error from slice"))?;

            if req.method == "org.varlink.service.GetInfo" {
                req.method = "org.varlink.resolver.GetInfo".into();
            }

            let n: usize = match req.method.rfind('.') {
                None => {
                    let method: String = String::from(req.method.as_ref());
                    let mut call = Call::new(&mut client_writer, &req);
                    call.reply_interface_not_found(Some(method))?;
                    return Ok(false);
                }
                Some(x) => x,
            };

            let iface = {
                if req.method == "org.varlink.service.GetInterfaceDescription" {
                    let val = req.parameters.clone().unwrap_or_default();
                    let args: GetInterfaceDescriptionArgs = from_value(val)?;
                    args.interface.into()
                } else {
                    String::from(&req.method[..n])
                }
            };

            if iface != last_iface {
                if iface.eq("org.varlink.resolver") {
                    address = String::from("unix:/run/org.varlink.resolver");
                } else {
                    address = match resolver.resolve(iface.clone()).call() {
                        Ok(r) => r.address,
                        _ => {
                            let mut call = Call::new(&mut client_writer, &req);
                            call.reply_interface_not_found(Some(iface))?;
                            return Ok(false);
                        }
                    };
                }
                last_iface = iface.clone();
            }

            let mut stream = match VarlinkStream::connect(&address) {
                Ok((a, _)) => a,
                _ => {
                    let mut call = Call::new(&mut client_writer, &req);
                    call.reply_interface_not_found(Some(iface))?;
                    return Ok(false);
                }
            };

            let (_, mut service_writer) = stream.split()?;
            let service_reader = WatchClose::new_read(&stream, &client_writer)?;
            let mut service_bufreader = ::std::io::BufReader::new(service_reader);

            last_service_stream = Some(stream);

            {
                let b = to_string(&req)? + "\0";

                service_writer.write_all(b.as_bytes())?;
                service_writer.flush()?;
            }

            if req.oneway.unwrap_or(false) {
                continue;
            }

            upgraded = req.upgrade.unwrap_or(false);

            loop {
                let mut buf = Vec::new();

                if service_bufreader.read_until(0, &mut buf)? == 0 {
                    break;
                }
                if buf.is_empty() {
                    return Err(strerr!("Connection Closed").into());
                }

                client_writer.write_all(&buf)?;
                client_writer.flush()?;

                buf.pop();

                let reply: Reply = from_slice(&buf)?;

                if upgraded || (!reply.continues.unwrap_or(false)) {
                    break;
                }
            }
        } else if let Some(ref mut service_stream) = last_service_stream {
            let (_, service_writer) = service_stream.split()?;
            let service_reader = WatchClose::new_read(service_stream, &client_writer)?;
            let client_reader = WatchClose::new_read(&client_reader_o, service_stream)?;

            use std::sync::mpsc::channel;
            let (tx_end, rx_end) = channel();

            // Should copy back and forth, until someone disconnects.
            {
                let copy1 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut client_reader = client_reader;
                    let mut service_writer = service_writer;

                    move || {
                        let r = copy(&mut client_reader, &mut service_writer);
                        tx_end.send(1).expect("channel should be open");
                        r
                    }
                });

                let copy2 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut service_reader = service_reader;

                    move || {
                        let r = copy(&mut service_reader, &mut client_writer);
                        tx_end.send(2).expect("channel should be open");
                        r
                    }
                });

                let end_tid = rx_end.recv()?;

                match end_tid {
                    1 => {
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = service_stream.shutdown();
                        unsafe { libc::close(service_stream.as_raw_fd()) };
                        r1?;

                        let _ = rx_end.recv()?;
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r2?;
                    }

                    2 => {
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = service_stream.shutdown();
                        unsafe { libc::close(service_stream.as_raw_fd()) };
                        r2?;

                        let _ = rx_end.recv()?;
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r1?;
                    }
                    _ => panic!("Unknown"),
                };
            }
            return Ok(true);
        }
         else {
            unreachable!();
        }

    }
    Ok(upgraded)
}

pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where
    R: Read,
    W: Write,
{
    use std::io::ErrorKind;
    use std::mem;

    let mut buf = unsafe {
        let mut buf: [u8; 8192] = mem::uninitialized();
        //reader.initializer().initialize(&mut buf);
        std::ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len());
        buf
    };

    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        writer.flush()?;
        written += len as u64;
    }
}

pub fn handle_connect<R, W>(
    connection: Arc<RwLock<Connection>>,
    client_reader_o: R,
    mut client_writer: W,
) -> Result<bool>
where
    R: Read + AsRawFd + Send + 'static,
    W: Write + AsRawFd + Send + 'static,
{
    let mut upgraded = false;

    let mut conn = connection.write().unwrap();

    if conn.stream.is_none() {
        return Err(varlink::context!(ErrorKind::ConnectionBusy).into());
    }

    let mut stream = conn.stream.take().unwrap();
    let mut service_writer = unsafe { ::std::fs::File::from_raw_fd(stream.as_raw_fd()) };

    let mut service_reader =
        ::std::io::BufReader::new(WatchClose::new_read(&stream, &client_writer)?);

    let mut client_reader =
        ::std::io::BufReader::new(WatchClose::new_read(&client_reader_o, &stream)?);

    loop {
        if !upgraded {
            let mut buf = Vec::new();
            match client_reader.read_until(b'\0', &mut buf) {
                Ok(0) => break,
                Err(_e) => break,
                _ => {}
            }

            // pop the last zero byte
            buf.pop();

            let req: Request = from_slice(&buf)?;

            {
                buf.push(0);
                service_writer.write_all(&buf)?;
                service_writer.flush()?;
            }

            if req.oneway.unwrap_or(false) {
                continue;
            }

            upgraded = req.upgrade.unwrap_or(false);

            loop {
                let mut buf = Vec::new();

                if service_reader.read_until(0, &mut buf)? == 0 {
                    break;
                }
                if buf.is_empty() {
                    return Err(strerr!("Connection Closed!").into());
                }

                client_writer.write_all(&buf)?;
                client_writer.flush()?;

                buf.pop();

                let reply: Reply = from_slice(&buf)?;

                if upgraded || !reply.continues.unwrap_or(false) {
                    break;
                }
            }
        } else {
            use std::sync::mpsc::channel;
            let (tx_end, rx_end) = channel();

            // Should copy back and forth, until someone disconnects.
            {
                let copy1 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut client_reader = WatchClose::new_read(&client_reader_o, &stream)?;

                    move || {
                        let r = copy(&mut client_reader, &mut service_writer);
                        tx_end.send(1).expect("channel should be open");
                        r
                    }
                });

                let copy2 = thread::spawn({
                    let tx_end = tx_end.clone();
                    let mut service_reader = WatchClose::new_read(&stream, &client_writer)?;

                    move || {
                        let r = copy(&mut service_reader, &mut client_writer);
                        tx_end.send(2).expect("channel should be open");
                        r
                    }
                });

                let end_tid = rx_end.recv()?;

                match end_tid {
                    1 => {
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = stream.shutdown();
                        unsafe { libc::close(stream.as_raw_fd()) };
                        r1?;

                        let _ = rx_end.recv()?;
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r2?;
                    }

                    2 => {
                        let r2 = copy2.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        let _ = stream.shutdown();
                        unsafe { libc::close(stream.as_raw_fd()) };
                        r2?;

                        let _ = rx_end.recv()?;
                        let r1 = copy1.join().unwrap_or_else(|_| Err(io::Error::from(io::ErrorKind::BrokenPipe)));

                        r1?;
                    }
                    _ => panic!("Unknown"),
                };
            }
            return Ok(true);
        }
    }
    Ok(upgraded)
}
<|endoftext|>


<commit_before>//! oracle metadata fetcher

use retry;
use metadata;
use errors::*;

use openssh_keys::PublicKey;

#[derive(Debug, Deserialize, Clone)]
struct InstanceData {
    #[serde(rename = "availabilityDomain")]
    availability_domain: String,
    #[serde(rename = "compartmentId")]
    compartment_id: String,
    #[serde(rename = "displayName")]
    display_name: String,
    id: String,
    image: String,
    region: String,
    shape: String,
    #[serde(rename = "timeCreated")]
    time_created: u64,
    metadata: Metadata,
}

#[derive(Debug, Deserialize, Clone)]
struct Metadata {
    #[serde(default)]
    ssh_authorized_keys: String,
}

pub fn fetch_metadata() -> Result<metadata::Metadata> {
    let client = retry::Client::new()
        .chain_err(|| "oracle: failed to create http client")?;

    let data: InstanceData = client.get(retry::Json, "http://169.254.169.254/opc/v1/instance/".into()).send()
        .chain_err(|| "oracle: failed to get instance metadata from metadata service")?
        .ok_or_else(|| "oracle: failed to get instance metadata from metadata service: no response")?;

    let ssh_keys = PublicKey::read_keys(data.metadata.ssh_authorized_keys.as_bytes())?;

    Ok(metadata::Metadata::builder()
        .add_attribute("ORACLE_OCI_DISPLAY_NAME".into(), data.display_name)
        .add_attribute("ORACLE_OCI_INSTANCE_ID".into(), data.id)
        .add_attribute("ORACLE_OCI_REGION".into(), data.region)
        .add_publickeys(ssh_keys)
        .build())
}
<commit_msg>providers/oracle: always say oracle-oci<commit_after>//! oracle-oci metadata fetcher

use retry;
use metadata;
use errors::*;

use openssh_keys::PublicKey;

#[derive(Debug, Deserialize, Clone)]
struct InstanceData {
    #[serde(rename = "availabilityDomain")]
    availability_domain: String,
    #[serde(rename = "compartmentId")]
    compartment_id: String,
    #[serde(rename = "displayName")]
    display_name: String,
    id: String,
    image: String,
    region: String,
    shape: String,
    #[serde(rename = "timeCreated")]
    time_created: u64,
    metadata: Metadata,
}

#[derive(Debug, Deserialize, Clone)]
struct Metadata {
    #[serde(default)]
    ssh_authorized_keys: String,
}

pub fn fetch_metadata() -> Result<metadata::Metadata> {
    let client = retry::Client::new()
        .chain_err(|| "oracle-oci: failed to create http client")?;

    let data: InstanceData = client.get(retry::Json, "http://169.254.169.254/opc/v1/instance/".into()).send()
        .chain_err(|| "oracle-oci: failed to get instance metadata from metadata service")?
        .ok_or_else(|| "oracle-oci: failed to get instance metadata from metadata service: no response")?;

    let ssh_keys = PublicKey::read_keys(data.metadata.ssh_authorized_keys.as_bytes())?;

    Ok(metadata::Metadata::builder()
        .add_attribute("ORACLE_OCI_DISPLAY_NAME".into(), data.display_name)
        .add_attribute("ORACLE_OCI_INSTANCE_ID".into(), data.id)
        .add_attribute("ORACLE_OCI_REGION".into(), data.region)
        .add_publickeys(ssh_keys)
        .build())
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use enums;
use parse;

pub fn write_descriptor_sets(doc: &parse::Spirv) -> String {
    // TODO: not implemented

    // finding all the descriptors
    let mut descriptors = Vec::new();
    struct Descriptor {
        name: String,
        desc_ty: String,
        bind_ty: String,
        bind: String,
        set: u32,
        binding: u32,
    }

    // looping to find all the elements that have the `DescriptorSet` decoration
    for instruction in doc.instructions.iter() {
        let (variable_id, descriptor_set) = match instruction {
            &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationDescriptorSet, ref params } => {
                (target_id, params[0])
            },
            _ => continue
        };

        // find which type is pointed to by this variable
        let pointed_ty = pointer_variable_ty(doc, variable_id);
        // name of the variable
        let name = ::name_from_id(doc, variable_id);

        // find the binding point of this descriptor
        let binding = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationBinding, ref params } if target_id == variable_id => {
                    Some(params[0])
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Uniform `{}` is missing a binding", name));

        // find informations about the kind of binding for this descriptor
        let (desc_ty, bind_ty, bind) = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::TypeStruct { result_id, .. } if result_id == pointed_ty => {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::UniformBuffer",
                        "::vulkano::buffer::AbstractBuffer",
                        "::vulkano::descriptor_set::DescriptorBind::UniformBuffer { buffer: data, offset: 0, size: 128 /* FIXME */ }"
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(true) =>
                {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::CombinedImageSampler",
                        "::vulkano::image::AbstractImageView",
                        "::vulkano::descriptor_set::DescriptorBind::CombinedImageSampler(data.0, data.1, ::vulkano::image::Layout::ShaderReadOnlyOptimal)"      // FIXME:
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(false) =>
                {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::InputAttachment",       // FIXME: can be `StorageImage`
                        "::vulkano::image::AbstractImageView",
                        "::vulkano::descriptor_set::DescriptorBind::InputAttachment(data, ::vulkano::image::Layout::ShaderReadOnlyOptimal)"     // FIXME:
                    ))
                },
                &parse::Instruction::TypeSampledImage { result_id, image_type_id }
                                                                    if result_id == pointed_ty =>
                {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::SampledImage",
                        "::vulkano::image::AbstractImageView",
                        "::vulkano::descriptor_set::DescriptorBind::SampledImage(data, ::vulkano::image::Layout::ShaderReadOnlyOptimal)"      // FIXME:
                    ))
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)", name, pointed_ty));

        descriptors.push(Descriptor {
            name: name,
            desc_ty: desc_ty.to_owned(),
            bind_ty: bind_ty.to_owned(),
            bind: bind.to_owned(),
            set: descriptor_set,
            binding: binding,
        });
    }

    let sets_list = descriptors.iter().map(|d| d.set).collect::<HashSet<u32>>();

    let mut output = String::new();

    // iterate once per set that is defined somewhere
    for set in sets_list.iter() {
        let write_ty = descriptors.iter().filter(|d| d.set == *set)
                                  .map(|d| format!("::std::sync::Arc<{}>", d.bind_ty))
                                  .collect::<Vec<_>>();

        let writes = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                                .map(|(entry, d)| {
                                    let entry = if write_ty.len() == 1 {
                                        "".to_owned()
                                    } else {
                                        format!(".{}", entry)
                                    };

                                    format!("{{ let data = data{entry};
                                            ::vulkano::descriptor_set::DescriptorWrite {{
                                                 binding: {binding},
                                                 array_element: 0,
                                                 content: {bind},
                                             }} }}", binding = d.binding, bind = d.bind,
                                                     entry = entry)
                                })
                                .collect::<Vec<_>>();

        let write_ty = if write_ty.len() == 1 {
            write_ty.into_iter().next().unwrap()
        } else {
            format!("({})", write_ty.join(", "))
        };

        let descr = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                               .map(|(entry, d)| {
                                   format!("::vulkano::descriptor_set::DescriptorDesc {{
                                                binding: {binding},
                                                ty: {desc_ty},
                                                array_count: 1,
                                                stages: ::vulkano::descriptor_set::ShaderStages::all_graphics(),        // TODO:
                                            }}", binding = d.binding, desc_ty = d.desc_ty)
                               })
                               .collect::<Vec<_>>();

        output.push_str(&format!(r#"
#[derive(Default)]
pub struct Set{set};

unsafe impl ::vulkano::descriptor_set::SetLayout for Set{set} {{
    fn descriptors(&self) -> Vec<::vulkano::descriptor_set::DescriptorDesc> {{
        vec![
            {descr}
        ]
    }}
}}

unsafe impl ::vulkano::descriptor_set::SetLayoutWrite<{write_ty}> for Set{set} {{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        vec![
            {writes}
        ]
    }}
}}

unsafe impl ::vulkano::descriptor_set::SetLayoutInit<{write_ty}> for Set{set} {{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        ::vulkano::descriptor_set::SetLayoutWrite::decode(self, data)
    }}
}}

"#, set = set, write_ty = write_ty, writes = writes.join(","), descr = descr.join(",")));
    }

    let max_set = sets_list.iter().cloned().max().map(|v| v + 1).unwrap_or(0);

    let sets_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSet<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let sets = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if sets_defs.len() == 1 {
                format!("sets")
            } else {
                format!("sets.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    let layouts_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSetLayout<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let layouts = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if layouts_defs.len() == 1 {
                format!("layouts")
            } else {
                format!("layouts.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    output.push_str(&format!(r#"
#[derive(Default)]
pub struct Layout;

unsafe impl ::vulkano::descriptor_set::Layout for Layout {{
    type DescriptorSets = ({sets_defs});
    type DescriptorSetLayouts = ({layouts_defs});
    type PushConstants = ();

    fn decode_descriptor_set_layouts(&self, layouts: Self::DescriptorSetLayouts)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSetLayout>>
    {{
        vec![
            {layouts}
        ]
    }}

    fn decode_descriptor_sets(&self, sets: Self::DescriptorSets)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSet>>
    {{
        vec![
            {sets}
        ]
    }}
}}
"#, sets_defs = sets_defs.join(","), layouts_defs = layouts_defs.join(","),
    layouts = layouts.join(","), sets = sets.join(",")));

    output
}

/// Assumes that `variable` is a variable with a `TypePointer` and returns the id of the pointed
/// type.
fn pointer_variable_ty(doc: &parse::Spirv, variable: u32) -> u32 {
    let var_ty = doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::Variable { result_type_id, result_id, .. } if result_id == variable => {
                Some(result_type_id)
            },
            _ => None
        }
    }).next().unwrap();

    doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == var_ty => {
                Some(type_id)
            },
            _ => None
        }
    }).next().unwrap()
}
<commit_msg>Fix wrong descriptor write being generated by ther shader parser<commit_after>use std::collections::HashSet;

use enums;
use parse;

pub fn write_descriptor_sets(doc: &parse::Spirv) -> String {
    // TODO: not implemented

    // finding all the descriptors
    let mut descriptors = Vec::new();
    struct Descriptor {
        name: String,
        desc_ty: String,
        bind_ty: String,
        bind: String,
        set: u32,
        binding: u32,
    }

    // looping to find all the elements that have the `DescriptorSet` decoration
    for instruction in doc.instructions.iter() {
        let (variable_id, descriptor_set) = match instruction {
            &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationDescriptorSet, ref params } => {
                (target_id, params[0])
            },
            _ => continue
        };

        // find which type is pointed to by this variable
        let pointed_ty = pointer_variable_ty(doc, variable_id);
        // name of the variable
        let name = ::name_from_id(doc, variable_id);

        // find the binding point of this descriptor
        let binding = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationBinding, ref params } if target_id == variable_id => {
                    Some(params[0])
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Uniform `{}` is missing a binding", name));

        // find informations about the kind of binding for this descriptor
        let (desc_ty, bind_ty, bind) = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::TypeStruct { result_id, .. } if result_id == pointed_ty => {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::UniformBuffer",
                        "::std::sync::Arc<::vulkano::buffer::AbstractBuffer>",
                        "::vulkano::descriptor_set::DescriptorBind::UniformBuffer { buffer: data, offset: 0, size: 128 /* FIXME */ }"
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(true) =>
                {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::SampledImage",
                        "::std::sync::Arc<::vulkano::image::AbstractImageView>",
                        "::vulkano::descriptor_set::DescriptorBind::SampledImage(data, ::vulkano::image::Layout::ShaderReadOnlyOptimal)"      // FIXME:
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(false) =>
                {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::InputAttachment",       // FIXME: can be `StorageImage`
                        "::std::sync::Arc<::vulkano::image::AbstractImageView>",
                        "::vulkano::descriptor_set::DescriptorBind::InputAttachment(data, ::vulkano::image::Layout::ShaderReadOnlyOptimal)"     // FIXME:
                    ))
                },
                &parse::Instruction::TypeSampledImage { result_id, image_type_id }
                                                                    if result_id == pointed_ty =>
                {
                    Some((
                        "::vulkano::descriptor_set::DescriptorType::CombinedImageSampler",
                        "(::std::sync::Arc<::vulkano::sampler::Sampler>, ::std::sync::Arc<::vulkano::image::AbstractImageView>)",
                        "::vulkano::descriptor_set::DescriptorBind::CombinedImageSampler(data.0, data.1, ::vulkano::image::Layout::ShaderReadOnlyOptimal)"      // FIXME:
                    ))
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)", name, pointed_ty));

        descriptors.push(Descriptor {
            name: name,
            desc_ty: desc_ty.to_owned(),
            bind_ty: bind_ty.to_owned(),
            bind: bind.to_owned(),
            set: descriptor_set,
            binding: binding,
        });
    }

    let sets_list = descriptors.iter().map(|d| d.set).collect::<HashSet<u32>>();

    let mut output = String::new();

    // iterate once per set that is defined somewhere
    for set in sets_list.iter() {
        let write_ty = descriptors.iter().filter(|d| d.set == *set)
                                  .map(|d| d.bind_ty.clone())
                                  .collect::<Vec<_>>();

        let writes = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                                .map(|(entry, d)| {
                                    let entry = if write_ty.len() == 1 {
                                        "".to_owned()
                                    } else {
                                        format!(".{}", entry)
                                    };

                                    format!("{{ let data = data{entry};
                                            ::vulkano::descriptor_set::DescriptorWrite {{
                                                 binding: {binding},
                                                 array_element: 0,
                                                 content: {bind},
                                             }} }}", binding = d.binding, bind = d.bind,
                                                     entry = entry)
                                })
                                .collect::<Vec<_>>();

        let write_ty = if write_ty.len() == 1 {
            write_ty.into_iter().next().unwrap()
        } else {
            format!("({})", write_ty.join(", "))
        };

        let descr = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                               .map(|(entry, d)| {
                                   format!("::vulkano::descriptor_set::DescriptorDesc {{
                                                binding: {binding},
                                                ty: {desc_ty},
                                                array_count: 1,
                                                stages: ::vulkano::descriptor_set::ShaderStages::all_graphics(),        // TODO:
                                            }}", binding = d.binding, desc_ty = d.desc_ty)
                               })
                               .collect::<Vec<_>>();

        output.push_str(&format!(r#"
#[derive(Default)]
pub struct Set{set};

unsafe impl ::vulkano::descriptor_set::SetLayout for Set{set} {{
    fn descriptors(&self) -> Vec<::vulkano::descriptor_set::DescriptorDesc> {{
        vec![
            {descr}
        ]
    }}
}}

unsafe impl ::vulkano::descriptor_set::SetLayoutWrite<{write_ty}> for Set{set} {{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        vec![
            {writes}
        ]
    }}
}}

unsafe impl ::vulkano::descriptor_set::SetLayoutInit<{write_ty}> for Set{set} {{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        ::vulkano::descriptor_set::SetLayoutWrite::decode(self, data)
    }}
}}

"#, set = set, write_ty = write_ty, writes = writes.join(","), descr = descr.join(",")));
    }

    let max_set = sets_list.iter().cloned().max().map(|v| v + 1).unwrap_or(0);

    let sets_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSet<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let sets = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if sets_defs.len() == 1 {
                format!("sets")
            } else {
                format!("sets.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    let layouts_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSetLayout<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let layouts = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if layouts_defs.len() == 1 {
                format!("layouts")
            } else {
                format!("layouts.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    output.push_str(&format!(r#"
#[derive(Default)]
pub struct Layout;

unsafe impl ::vulkano::descriptor_set::Layout for Layout {{
    type DescriptorSets = ({sets_defs});
    type DescriptorSetLayouts = ({layouts_defs});
    type PushConstants = ();

    fn decode_descriptor_set_layouts(&self, layouts: Self::DescriptorSetLayouts)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSetLayout>>
    {{
        vec![
            {layouts}
        ]
    }}

    fn decode_descriptor_sets(&self, sets: Self::DescriptorSets)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSet>>
    {{
        vec![
            {sets}
        ]
    }}
}}
"#, sets_defs = sets_defs.join(","), layouts_defs = layouts_defs.join(","),
    layouts = layouts.join(","), sets = sets.join(",")));

    output
}

/// Assumes that `variable` is a variable with a `TypePointer` and returns the id of the pointed
/// type.
fn pointer_variable_ty(doc: &parse::Spirv, variable: u32) -> u32 {
    let var_ty = doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::Variable { result_type_id, result_id, .. } if result_id == variable => {
                Some(result_type_id)
            },
            _ => None
        }
    }).next().unwrap();

    doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == var_ty => {
                Some(type_id)
            },
            _ => None
        }
    }).next().unwrap()
}
<|endoftext|>


<commit_before>#![cfg(unix)]

use assert_cmd::Command;
use tempfile::tempdir;

use std::{
    env::{consts::DLL_SUFFIX, var_os},
    ffi::OsString,
    fs::{self, create_dir, create_dir_all, remove_file, set_permissions, File},
    io::Write,
    os::unix::{
        fs::symlink,
        prelude::{OsStrExt, PermissionsExt},
    },
    path::{Path, PathBuf},
};

struct StopServer;
impl Drop for StopServer {
    fn drop(&mut self) {
        let _ = Command::cargo_bin("sccache")
            .unwrap()
            .arg("--stop-server")
            .ok();
    }
}

// (temp dir)
// ├── rust // symlinks to rust1 on the first run and rust2 on the second
// ├── rust1/
// │  ├── bin
// │  │  └── rustc
// │  ├── lib
// │  │  └── driver.so -> ../driver.so
// │  └── driver.so
// ├── rust2/
// │  ├── bin
// │  │  └── rustc
// │  ├── lib
// │  │  └── driver.so -> ../driver.so
// │  └── driver.so
// ├── sccache/
// ├── counter // increases by 1 for every compilation that is not cached
// ├── RUST_FILE // compile output copied from counter, same content means it was cached
// └── RUST_FILE.rs
#[test]
fn test_symlinks() {
    let root = tempdir().unwrap();
    let root = root.path();

    fs::write(root.join("counter"), b"0").unwrap();
    fs::write(root.join("RUST_FILE.rs"), []).unwrap();

    create_mock_rustc(root.join("rust1"));
    create_mock_rustc(root.join("rust2"));

    let rust = root.join("rust");
    let bin = rust.join("bin");
    let out_file = root.join("RUST_FILE");

    symlink(root.join("rust1"), &rust).unwrap();
    drop(StopServer);
    let _stop_server = StopServer;
    run_sccache(root, &bin);
    let output1 = fs::read(&out_file).unwrap();

    remove_file(&rust).unwrap();
    symlink(root.join("rust2"), &rust).unwrap();
    run_sccache(root, &bin);
    let output2 = fs::read(out_file).unwrap();

    assert_ne!(output1, output2);
}

fn create_mock_rustc(dir: PathBuf) {
    let bin = dir.join("bin");
    create_dir_all(&bin).unwrap();

    let dll_name = format!("driver{DLL_SUFFIX}");
    let dll = dir.join(&dll_name);
    fs::write(&dll, dir.as_os_str().as_bytes()).unwrap();

    let lib = dir.join("lib");
    create_dir(&lib).unwrap();
    symlink(dll, lib.join(&dll_name)).unwrap();

    let rustc = bin.join("rustc");
    write!(
        File::create(&rustc).unwrap(),
        r#"#!/usr/bin/env bash

set -e
build=0

while (( "$#" )); do
    case "$1" in
        -vV)
            echo rustc 1.0.0
            exec echo "host: unknown"
            ;;
        --print=sysroot)
            exec echo {}
            ;;
        --print)
            shift
            if [ "$1" = file-names ]; then
                exec echo RUST_FILE.rs
            fi
            ;;
        --emit)
            shift
            if [ "$1" = dep-info ]; then
                echo "deps.d: RUST_FILE.rs" > "$3"
                exec echo "RUST_FILE.rs:" "$3"
            fi
            ;;
        RUST_FILE.rs)
            build=1
            ;;
    esac
    shift
done

if (( $build )); then
    echo $(("$(cat counter)" + 1)) > counter
    cp counter RUST_FILE
fi
"#,
        dir.display(),
    )
    .unwrap();

    let mut perm = rustc.metadata().unwrap().permissions();
    perm.set_mode(0o755);
    set_permissions(&rustc, perm).unwrap();
}

fn run_sccache(root: &Path, path: &Path) {
    let mut paths: OsString = path.into();
    paths.push(":");
    paths.push(var_os("PATH").unwrap());

    Command::cargo_bin("sccache")
        .unwrap()
        .current_dir(root)
        .env("PATH", paths)
        .env("SCCACHE_DIR", root.join("sccache"))
        .arg("rustc")
        .arg("RUST_FILE.rs")
        .arg("--crate-name=sccache_rustc_tests")
        .arg("--crate-type=lib")
        .arg("--emit=link")
        .arg("--out-dir")
        .arg(root)
        .unwrap();
}
<commit_msg>fix test_symlinks when rustup is in PATH<commit_after>#![cfg(unix)]

use assert_cmd::Command;
use tempfile::tempdir;

use std::{
    env::{consts::DLL_SUFFIX, var_os},
    ffi::OsString,
    fs::{self, create_dir, create_dir_all, remove_file, set_permissions, File},
    io::Write,
    os::unix::{
        fs::symlink,
        prelude::{OsStrExt, PermissionsExt},
    },
    path::{Path, PathBuf},
};

struct StopServer;
impl Drop for StopServer {
    fn drop(&mut self) {
        let _ = Command::cargo_bin("sccache")
            .unwrap()
            .arg("--stop-server")
            .ok();
    }
}

// (temp dir)
// ├── rust // symlinks to rust1 on the first run and rust2 on the second
// ├── rust1/
// │  ├── bin
// │  │  └── rustc
// │  ├── lib
// │  │  └── driver.so -> ../driver.so
// │  └── driver.so
// ├── rust2/
// │  ├── bin
// │  │  └── rustc
// │  ├── lib
// │  │  └── driver.so -> ../driver.so
// │  └── driver.so
// ├── sccache/
// ├── counter // increases by 1 for every compilation that is not cached
// ├── RUST_FILE // compile output copied from counter, same content means it was cached
// └── RUST_FILE.rs
#[test]
fn test_symlinks() {
    let root = tempdir().unwrap();
    let root = root.path();

    fs::write(root.join("counter"), b"0").unwrap();
    fs::write(root.join("RUST_FILE.rs"), []).unwrap();

    create_mock_rustc(root.join("rust1"));
    create_mock_rustc(root.join("rust2"));

    let rust = root.join("rust");
    let bin = rust.join("bin");
    let out_file = root.join("RUST_FILE");

    symlink(root.join("rust1"), &rust).unwrap();
    drop(StopServer);
    let _stop_server = StopServer;
    run_sccache(root, &bin);
    let output1 = fs::read(&out_file).unwrap();

    remove_file(&rust).unwrap();
    symlink(root.join("rust2"), &rust).unwrap();
    run_sccache(root, &bin);
    let output2 = fs::read(out_file).unwrap();

    assert_ne!(output1, output2);
}

fn create_mock_rustc(dir: PathBuf) {
    let bin = dir.join("bin");
    create_dir_all(&bin).unwrap();

    let dll_name = format!("driver{DLL_SUFFIX}");
    let dll = dir.join(&dll_name);
    fs::write(&dll, dir.as_os_str().as_bytes()).unwrap();

    let lib = dir.join("lib");
    create_dir(&lib).unwrap();
    symlink(dll, lib.join(&dll_name)).unwrap();

    let rustc = bin.join("rustc");
    write!(
        File::create(&rustc).unwrap(),
        r#"#!/usr/bin/env bash

set -e
build=0

while (( "$#" )); do
    case "$1" in
        -vV)
            echo rustc 1.0.0
            exec echo "host: unknown"
            ;;
        +stable)
            exit 1
            ;;
        --print=sysroot)
            exec echo {}
            ;;
        --print)
            shift
            if [ "$1" = file-names ]; then
                exec echo RUST_FILE.rs
            fi
            ;;
        --emit)
            shift
            if [ "$1" = dep-info ]; then
                echo "deps.d: RUST_FILE.rs" > "$3"
                exec echo "RUST_FILE.rs:" "$3"
            fi
            ;;
        RUST_FILE.rs)
            build=1
            ;;
    esac
    shift
done

if (( $build )); then
    echo $(("$(cat counter)" + 1)) > counter
    cp counter RUST_FILE
fi
"#,
        dir.display(),
    )
    .unwrap();

    let mut perm = rustc.metadata().unwrap().permissions();
    perm.set_mode(0o755);
    set_permissions(&rustc, perm).unwrap();
}

fn run_sccache(root: &Path, path: &Path) {
    let mut paths: OsString = path.into();
    paths.push(":");
    paths.push(var_os("PATH").unwrap());

    Command::cargo_bin("sccache")
        .unwrap()
        .current_dir(root)
        .env("PATH", paths)
        .env("SCCACHE_DIR", root.join("sccache"))
        .arg("rustc")
        .arg("RUST_FILE.rs")
        .arg("--crate-name=sccache_rustc_tests")
        .arg("--crate-type=lib")
        .arg("--emit=link")
        .arg("--out-dir")
        .arg(root)
        .unwrap();
}
<|endoftext|>


<commit_before>use gmp::mpq::Mpq;
use gmp::mpz::Mpz;
use std::borrow::Borrow;
use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, stdin};
use std::result::Result;
use std::str::FromStr;

pub struct BallotParser {
    pub candidates: Vec<String>,
    pub candidate_index: HashMap<String, usize>,
    pub ballots: Vec<(Box<[Box<[usize]>]>, Mpq)>,
}

fn parse_rational(s: &str) -> Result<Mpq, ()> {
    match s.find('/') {
        Some(i) => Ok(Mpq::ratio(&Mpz::from_str(&s[..i])?, &Mpz::from_str(&s[i + 1..])?)),
        None => Ok(Mpq::ratio(&Mpz::from_str(s)?, &Mpz::one())),
    }
}

impl BallotParser {
    fn new() -> BallotParser {
        BallotParser {
            candidates: Vec::new(),
            candidate_index: HashMap::new(),
            ballots: Vec::new(),
        }
    }

    fn parse_candidate(&mut self, name: &str) -> usize {
        let name = name.trim();
        match self.candidate_index.entry(name.to_string()) {
            Entry::Occupied(e) => *e.get(),
            Entry::Vacant(e) => {
                let n = self.candidates.len();
                e.insert(n);
                self.candidates.push(name.to_string());
                n
            }
        }
    }

    fn parse_group(&mut self, group: &str) -> Box<[usize]> {
        group.split('=')
            .map(|name| self.parse_candidate(name))
            .collect::<Vec<_>>()
            .into_boxed_slice()
    }

    fn parse_groups(&mut self, groups: &str) -> Box<[Box<[usize]>]> {
        groups.split('>')
            .map(|group| self.parse_group(group))
            .collect::<Vec<_>>()
            .into_boxed_slice()
    }

    fn add_ballot(&mut self, line: &str) -> Result<(), String> {
        let line = line.trim();
        if line.is_empty() {
            return Ok(());
        }

        let (w, groups) = match line.find(':') {
            Some(i) =>
                (parse_rational(&line[..i]).map_err(|()| "cannot parse ballot weight")?,
                 &line[i + 1..]),
            None => (Mpq::one(), &line[..]),
        };

        let ballot = (self.parse_groups(groups), w);
        self.ballots.push(ballot);
        Ok(())
    }

    fn add_ballots<R: Read>(&mut self, buf: BufReader<R>) -> Result<(), (usize, String)> {
        for (lineno, line) in buf.lines().enumerate() {
            self.add_ballot(&line.map_err(|e| (lineno, String::from(e.description())))?)
                .map_err(|e| (lineno, e))?;
        }
        Ok(())
    }

    fn add_ballot_file(&mut self, filename: &str) -> Result<(), String> {
        let file: Box<Read> = if filename == "-" {
            Box::new(stdin())
        } else {
            Box::new(File::open(filename).map_err(|e| format!("error: {}: {}", filename, e))?)
        };
        self.add_ballots(BufReader::new(file))
            .map_err(|(lineno, e)| format!("{}:{}: error: {}", filename, lineno + 1, e))
    }
}

pub fn parse_ballot_files<Str>(filenames: &[Str]) -> Result<BallotParser, String>
    where Str: Borrow<str>
{
    let mut bp = BallotParser::new();
    for filename in filenames.iter() {
        bp.add_ballot_file(filename.borrow())?;
    }
    Ok(bp)
}
<commit_msg>Check that ballot weights are positive<commit_after>use gmp::mpq::Mpq;
use gmp::mpz::Mpz;
use std::borrow::Borrow;
use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, stdin};
use std::result::Result;
use std::str::FromStr;

pub struct BallotParser {
    pub candidates: Vec<String>,
    pub candidate_index: HashMap<String, usize>,
    pub ballots: Vec<(Box<[Box<[usize]>]>, Mpq)>,
}

fn parse_rational(s: &str) -> Result<Mpq, ()> {
    match s.find('/') {
        Some(i) => Ok(Mpq::ratio(&Mpz::from_str(&s[..i])?, &Mpz::from_str(&s[i + 1..])?)),
        None => Ok(Mpq::ratio(&Mpz::from_str(s)?, &Mpz::one())),
    }
}

impl BallotParser {
    fn new() -> BallotParser {
        BallotParser {
            candidates: Vec::new(),
            candidate_index: HashMap::new(),
            ballots: Vec::new(),
        }
    }

    fn parse_candidate(&mut self, name: &str) -> usize {
        let name = name.trim();
        match self.candidate_index.entry(name.to_string()) {
            Entry::Occupied(e) => *e.get(),
            Entry::Vacant(e) => {
                let n = self.candidates.len();
                e.insert(n);
                self.candidates.push(name.to_string());
                n
            }
        }
    }

    fn parse_group(&mut self, group: &str) -> Box<[usize]> {
        group.split('=')
            .map(|name| self.parse_candidate(name))
            .collect::<Vec<_>>()
            .into_boxed_slice()
    }

    fn parse_groups(&mut self, groups: &str) -> Box<[Box<[usize]>]> {
        groups.split('>')
            .map(|group| self.parse_group(group))
            .collect::<Vec<_>>()
            .into_boxed_slice()
    }

    fn add_ballot(&mut self, line: &str) -> Result<(), String> {
        let line = line.trim();
        if line.is_empty() {
            return Ok(());
        }

        let (w, groups) = match line.find(':') {
            Some(i) => {
                let w = parse_rational(&line[..i]).map_err(|()| "cannot parse ballot weight")?;
                if w <= Mpq::zero() {
                    Err("non-positive ballot weight")?
                }
                (w, &line[i + 1..])
            }
            None => (Mpq::one(), &line[..]),
        };

        let ballot = (self.parse_groups(groups), w);
        self.ballots.push(ballot);
        Ok(())
    }

    fn add_ballots<R: Read>(&mut self, buf: BufReader<R>) -> Result<(), (usize, String)> {
        for (lineno, line) in buf.lines().enumerate() {
            self.add_ballot(&line.map_err(|e| (lineno, String::from(e.description())))?)
                .map_err(|e| (lineno, e))?;
        }
        Ok(())
    }

    fn add_ballot_file(&mut self, filename: &str) -> Result<(), String> {
        let file: Box<Read> = if filename == "-" {
            Box::new(stdin())
        } else {
            Box::new(File::open(filename).map_err(|e| format!("error: {}: {}", filename, e))?)
        };
        self.add_ballots(BufReader::new(file))
            .map_err(|(lineno, e)| format!("{}:{}: error: {}", filename, lineno + 1, e))
    }
}

pub fn parse_ballot_files<Str>(filenames: &[Str]) -> Result<BallotParser, String>
    where Str: Borrow<str>
{
    let mut bp = BallotParser::new();
    for filename in filenames.iter() {
        bp.add_ballot_file(filename.borrow())?;
    }
    Ok(bp)
}
<|endoftext|>


<commit_before>extern crate korome;
extern crate glium;

use korome::{Draw, Vector2, Game, Settings, InfoPacket, GameLogic};
use korome::draw::{Texture, TextureDrawer, Vertex, VertexBuffers};
use glium::VertexBuffer;

macro_rules! print_type_info{
    ($($t:ty),*) => {
        use std::mem::{align_of, size_of};
        $({
            let info = (size_of::<$t>(), align_of::<$t>());
            println!("{}\t: {} === {} * {}", stringify!($t), info.0, info.0/info.1, info.1);
        })*
    }
}

fn main(){
    print_type_info!(Logic, Draw, Vector2, Texture, Vertex, Game<Logic>, InfoPacket, Settings, TextureDrawer, VertexBuffers, VertexBuffer<Vertex>);
}

struct Logic;

impl GameLogic for Logic {
    fn logic (&mut self, _ip: InfoPacket){

    }

    fn render(&self, _target: &mut glium::Frame, _draw: &Draw){

    }
}
<commit_msg>Avoid conflicts<commit_after>extern crate korome;
extern crate glium;

use korome::{Draw, Vector2, Game, Settings, InfoPacket, GameLogic};
use korome::draw::{Texture, TextureDrawer, Vertex, VertexBuffers};
use glium::VertexBuffer;

macro_rules! print_type_info{
    ($($t:ty),*) => {
        $({
            use std::mem::{align_of, size_of};

            let info = (size_of::<$t>(), align_of::<$t>());
            println!("{}\t: {} === {} * {}", stringify!($t), info.0, info.0/info.1, info.1);
        })*
    }
}

fn main(){
    print_type_info!(Logic, Draw, Vector2, Texture, Vertex, Game<Logic>, InfoPacket, Settings, TextureDrawer, VertexBuffers, VertexBuffer<Vertex>);
}

struct Logic;

impl GameLogic for Logic {
    fn logic (&mut self, _ip: InfoPacket){

    }

    fn render(&self, _target: &mut glium::Frame, _draw: &Draw){

    }
}
<|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 dom::bindings::codegen::BindingDeclarations::HTMLTableColElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLTableColElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLTableColElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLTableColElement {
    pub htmlelement: HTMLElement,
}

impl HTMLTableColElementDerived for EventTarget {
    fn is_htmltablecolelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLTableColElementTypeId))
    }
}

impl HTMLTableColElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLTableColElement {
        HTMLTableColElement {
            htmlelement: HTMLElement::new_inherited(HTMLTableColElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLTableColElement> {
        let element = HTMLTableColElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLTableColElementBinding::Wrap)
    }
}

pub trait HTMLTableColElementMethods {
    fn Span(&self) -> u32;
    fn SetSpan(&mut self, _span: u32) -> ErrorResult;
    fn Align(&self) -> DOMString;
    fn SetAlign(&mut self, _align: DOMString) -> ErrorResult;
    fn Ch(&self) -> DOMString;
    fn SetCh(&mut self, _ch: DOMString) -> ErrorResult;
    fn ChOff(&self) -> DOMString;
    fn SetChOff(&mut self, _ch_off: DOMString) -> ErrorResult;
    fn VAlign(&self) -> DOMString;
    fn SetVAlign(&mut self, _v_align: DOMString) -> ErrorResult;
    fn Width(&self) -> DOMString;
    fn SetWidth(&mut self, _width: DOMString) -> ErrorResult;
}

impl<'a> HTMLTableColElementMethods for JSRef<'a, HTMLTableColElement> {
    fn Span(&self) -> u32 {
        0
    }

    fn SetSpan(&mut self, _span: u32) -> ErrorResult {
        Ok(())
    }

    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&mut self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Ch(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCh(&mut self, _ch: DOMString) -> ErrorResult {
        Ok(())
    }

    fn ChOff(&self) -> DOMString {
        "".to_owned()
    }

    fn SetChOff(&mut self, _ch_off: DOMString) -> ErrorResult {
        Ok(())
    }

    fn VAlign(&self) -> DOMString {
        "".to_owned()
    }

    fn SetVAlign(&mut self, _v_align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Width(&self) -> DOMString {
        "".to_owned()
    }

    fn SetWidth(&mut self, _width: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLTableColElementMethods.<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 dom::bindings::codegen::BindingDeclarations::HTMLTableColElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLTableColElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLTableColElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLTableColElement {
    pub htmlelement: HTMLElement,
}

impl HTMLTableColElementDerived for EventTarget {
    fn is_htmltablecolelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLTableColElementTypeId))
    }
}

impl HTMLTableColElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLTableColElement {
        HTMLTableColElement {
            htmlelement: HTMLElement::new_inherited(HTMLTableColElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLTableColElement> {
        let element = HTMLTableColElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLTableColElementBinding::Wrap)
    }
}

pub trait HTMLTableColElementMethods {
    fn Span(&self) -> u32;
    fn SetSpan(&self, _span: u32) -> ErrorResult;
    fn Align(&self) -> DOMString;
    fn SetAlign(&self, _align: DOMString) -> ErrorResult;
    fn Ch(&self) -> DOMString;
    fn SetCh(&self, _ch: DOMString) -> ErrorResult;
    fn ChOff(&self) -> DOMString;
    fn SetChOff(&self, _ch_off: DOMString) -> ErrorResult;
    fn VAlign(&self) -> DOMString;
    fn SetVAlign(&self, _v_align: DOMString) -> ErrorResult;
    fn Width(&self) -> DOMString;
    fn SetWidth(&self, _width: DOMString) -> ErrorResult;
}

impl<'a> HTMLTableColElementMethods for JSRef<'a, HTMLTableColElement> {
    fn Span(&self) -> u32 {
        0
    }

    fn SetSpan(&self, _span: u32) -> ErrorResult {
        Ok(())
    }

    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Ch(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCh(&self, _ch: DOMString) -> ErrorResult {
        Ok(())
    }

    fn ChOff(&self) -> DOMString {
        "".to_owned()
    }

    fn SetChOff(&self, _ch_off: DOMString) -> ErrorResult {
        Ok(())
    }

    fn VAlign(&self) -> DOMString {
        "".to_owned()
    }

    fn SetVAlign(&self, _v_align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Width(&self) -> DOMString {
        "".to_owned()
    }

    fn SetWidth(&self, _width: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>