<commit_before>use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::convert::AsRef;
use std::io;
use std::rc::Rc;

use asnom::structure::StructureTag;
use asnom::structures::{Tag, Sequence, Integer, OctetString, Boolean};
use asnom::common::TagClass::*;

use filter::parse;

use futures::{Async, Future, Poll, Stream};
use futures::sync::{mpsc, oneshot};
use tokio_proto::multiplex::RequestId;
use tokio_service::Service;

use ldap::{bundle, next_search_options};
use ldap::{Ldap, LdapOp};
use protocol::{LdapResult, ProtoBundle};

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Scope {
    Base     = 0,
    OneLevel = 1,
    Subtree  = 2,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DerefAliases {
    Never     = 0,
    Searching = 1,
    Finding   = 2,
    Always    = 3,
}

pub enum SearchItem {
    Entry(StructureTag),
    Referral(StructureTag),
    Done(RequestId, LdapResult, Option<StructureTag>),
}

pub struct SearchStream {
    id: RequestId,
    bundle: Rc<RefCell<ProtoBundle>>,
    _tx_i: mpsc::UnboundedSender<SearchItem>,
    rx_i: mpsc::UnboundedReceiver<SearchItem>,
    tx_r: Option<oneshot::Sender<(LdapResult, Option<StructureTag>)>>,
    refs: Vec<HashSet<String>>,
}

impl Stream for SearchStream {
    type Item = StructureTag;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            let item = try_ready!(self.rx_i.poll().map_err(|_e| io::Error::new(io::ErrorKind::Other, "poll search stream")));
            match item {
                Some(SearchItem::Done(_id, mut result, controls)) => {
                    result.refs.extend(self.refs.drain(..));
                    let mut bundle = self.bundle.borrow_mut();
                    let msgid = match bundle.search_helpers.get(&self.id) {
                        Some(ref helper) => helper.msgid,
                        None => return Ok(Async::Ready(None)),
                    };
                    bundle.search_helpers.remove(&self.id);
                    bundle.id_map.remove(&msgid);
                    let tx_r = self.tx_r.take().expect("oneshot tx");
                    tx_r.send((result, controls)).map_err(|_e| io::Error::new(io::ErrorKind::Other, "send result"))?;
                    return Ok(Async::Ready(None));
                },
                Some(SearchItem::Entry(tag)) => return Ok(Async::Ready(Some(tag))),
                Some(SearchItem::Referral(tag)) => {
                    self.refs.push(tag.expect_constructed().expect("referrals").into_iter()
                        .map(|t| t.expect_primitive().expect("octet string"))
                        .map(String::from_utf8)
                        .map(|s| s.expect("uri"))
                        .collect());
                    continue;
                },
                None => return Ok(Async::Ready(None)),
            }
        }
    }
}

#[derive(Debug)]
pub struct SearchEntry {
    dn: String,
    attrs: HashMap<String, Vec<String>>,
}

impl SearchEntry {
    pub fn construct(tag: StructureTag) -> SearchEntry {
        let mut tags = tag.match_id(4).and_then(|t| t.expect_constructed()).expect("entry").into_iter();
        let dn = String::from_utf8(tags.next().expect("element").expect_primitive().expect("octet string"))
            .expect("dn");
        let mut attr_vals = HashMap::new();
        let attrs = tags.next().expect("element").expect_constructed().expect("attrs").into_iter();
        for a_v in attrs {
            let mut part_attr = a_v.expect_constructed().expect("partial attribute").into_iter();
            let a_type = String::from_utf8(part_attr.next().expect("element").expect_primitive().expect("octet string"))
                .expect("attribute type");
            let values = part_attr.next().expect("element").expect_constructed().expect("values").into_iter()
                .map(|t| t.expect_primitive().expect("octet string"))
                .map(String::from_utf8)
                .map(|s| s.expect("value"))
                .collect();
            attr_vals.insert(a_type, values);
        }
        SearchEntry {
            dn: dn,
            attrs: attr_vals,
        }
    }
}

pub struct SearchOptions {
    deref: DerefAliases,
    typesonly: bool,
    timelimit: i32,
    sizelimit: i32,
}

impl SearchOptions {
    pub fn new() -> Self {
        SearchOptions {
            deref: DerefAliases::Never,
            typesonly: false,
            timelimit: 0,
            sizelimit: 0,
        }
    }

    pub fn deref(mut self, d: DerefAliases) -> Self {
        self.deref = d;
        self
    }

    pub fn typesonly(mut self, typesonly: bool) -> Self {
        self.typesonly = typesonly;
        self
    }

    pub fn timelimit(mut self, timelimit: i32) -> Self {
        self.timelimit = timelimit;
        self
    }

    pub fn sizelimit(mut self, sizelimit: i32) -> Self {
        self.sizelimit = sizelimit;
        self
    }
}

impl Ldap {
    pub fn search<S: AsRef<str>>(&self, base: &str, scope: Scope, filter: &str, attrs: Vec<S>) ->
        Box<Future<Item=(SearchStream, oneshot::Receiver<(LdapResult, Option<StructureTag>)>), Error=io::Error>> {
        let opts = match next_search_options(self) {
            Some(opts) => opts,
            None => SearchOptions::new(),
        };
        let req = Tag::Sequence(Sequence {
            id: 3,
            class: Application,
            inner: vec![
                   Tag::OctetString(OctetString {
                       inner: Vec::from(base.as_bytes()),
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: scope as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: opts.deref as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: opts.sizelimit as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: opts.timelimit as i64,
                       .. Default::default()
                   }),
                   Tag::Boolean(Boolean {
                       inner: opts.typesonly,
                       .. Default::default()
                   }),
                   parse(filter).unwrap(),
                   Tag::Sequence(Sequence {
                       inner: attrs.into_iter().map(|s|
                            Tag::OctetString(OctetString { inner: Vec::from(s.as_ref()), ..Default::default() })).collect(),
                       .. Default::default()
                   })
            ],
        });

        let (tx_i, rx_i) = mpsc::unbounded::<SearchItem>();
        let (tx_r, rx_r) = oneshot::channel::<(LdapResult, Option<StructureTag>)>();
        let bundle = bundle(self);
        let fut = self.call(LdapOp::Multi(req, tx_i.clone())).and_then(move |res| {
            let id = match res {
                (Tag::Integer(Integer { id: _, class: _, inner }), _) => inner,
                _ => unimplemented!(),
            };
            Ok((SearchStream {
                id: id as RequestId,
                bundle: bundle,
                _tx_i: tx_i,
                rx_i: rx_i,
                tx_r: Some(tx_r),
                refs: Vec::new(),
            }, rx_r))
        });

        Box::new(fut)
    }
}
<commit_msg>Fix scope/deref serialization<commit_after>use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::convert::AsRef;
use std::io;
use std::rc::Rc;

use asnom::structure::StructureTag;
use asnom::structures::{Boolean, Enumerated, Integer, OctetString, Sequence, Tag};
use asnom::common::TagClass::*;

use filter::parse;

use futures::{Async, Future, Poll, Stream};
use futures::sync::{mpsc, oneshot};
use tokio_proto::multiplex::RequestId;
use tokio_service::Service;

use ldap::{bundle, next_search_options};
use ldap::{Ldap, LdapOp};
use protocol::{LdapResult, ProtoBundle};

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Scope {
    Base     = 0,
    OneLevel = 1,
    Subtree  = 2,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DerefAliases {
    Never     = 0,
    Searching = 1,
    Finding   = 2,
    Always    = 3,
}

pub enum SearchItem {
    Entry(StructureTag),
    Referral(StructureTag),
    Done(RequestId, LdapResult, Option<StructureTag>),
}

pub struct SearchStream {
    id: RequestId,
    bundle: Rc<RefCell<ProtoBundle>>,
    _tx_i: mpsc::UnboundedSender<SearchItem>,
    rx_i: mpsc::UnboundedReceiver<SearchItem>,
    tx_r: Option<oneshot::Sender<(LdapResult, Option<StructureTag>)>>,
    refs: Vec<HashSet<String>>,
}

impl Stream for SearchStream {
    type Item = StructureTag;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            let item = try_ready!(self.rx_i.poll().map_err(|_e| io::Error::new(io::ErrorKind::Other, "poll search stream")));
            match item {
                Some(SearchItem::Done(_id, mut result, controls)) => {
                    result.refs.extend(self.refs.drain(..));
                    let mut bundle = self.bundle.borrow_mut();
                    let msgid = match bundle.search_helpers.get(&self.id) {
                        Some(ref helper) => helper.msgid,
                        None => return Ok(Async::Ready(None)),
                    };
                    bundle.search_helpers.remove(&self.id);
                    bundle.id_map.remove(&msgid);
                    let tx_r = self.tx_r.take().expect("oneshot tx");
                    tx_r.send((result, controls)).map_err(|_e| io::Error::new(io::ErrorKind::Other, "send result"))?;
                    return Ok(Async::Ready(None));
                },
                Some(SearchItem::Entry(tag)) => return Ok(Async::Ready(Some(tag))),
                Some(SearchItem::Referral(tag)) => {
                    self.refs.push(tag.expect_constructed().expect("referrals").into_iter()
                        .map(|t| t.expect_primitive().expect("octet string"))
                        .map(String::from_utf8)
                        .map(|s| s.expect("uri"))
                        .collect());
                    continue;
                },
                None => return Ok(Async::Ready(None)),
            }
        }
    }
}

#[derive(Debug)]
pub struct SearchEntry {
    dn: String,
    attrs: HashMap<String, Vec<String>>,
}

impl SearchEntry {
    pub fn construct(tag: StructureTag) -> SearchEntry {
        let mut tags = tag.match_id(4).and_then(|t| t.expect_constructed()).expect("entry").into_iter();
        let dn = String::from_utf8(tags.next().expect("element").expect_primitive().expect("octet string"))
            .expect("dn");
        let mut attr_vals = HashMap::new();
        let attrs = tags.next().expect("element").expect_constructed().expect("attrs").into_iter();
        for a_v in attrs {
            let mut part_attr = a_v.expect_constructed().expect("partial attribute").into_iter();
            let a_type = String::from_utf8(part_attr.next().expect("element").expect_primitive().expect("octet string"))
                .expect("attribute type");
            let values = part_attr.next().expect("element").expect_constructed().expect("values").into_iter()
                .map(|t| t.expect_primitive().expect("octet string"))
                .map(String::from_utf8)
                .map(|s| s.expect("value"))
                .collect();
            attr_vals.insert(a_type, values);
        }
        SearchEntry {
            dn: dn,
            attrs: attr_vals,
        }
    }
}

pub struct SearchOptions {
    deref: DerefAliases,
    typesonly: bool,
    timelimit: i32,
    sizelimit: i32,
}

impl SearchOptions {
    pub fn new() -> Self {
        SearchOptions {
            deref: DerefAliases::Never,
            typesonly: false,
            timelimit: 0,
            sizelimit: 0,
        }
    }

    pub fn deref(mut self, d: DerefAliases) -> Self {
        self.deref = d;
        self
    }

    pub fn typesonly(mut self, typesonly: bool) -> Self {
        self.typesonly = typesonly;
        self
    }

    pub fn timelimit(mut self, timelimit: i32) -> Self {
        self.timelimit = timelimit;
        self
    }

    pub fn sizelimit(mut self, sizelimit: i32) -> Self {
        self.sizelimit = sizelimit;
        self
    }
}

impl Ldap {
    pub fn search<S: AsRef<str>>(&self, base: &str, scope: Scope, filter: &str, attrs: Vec<S>) ->
        Box<Future<Item=(SearchStream, oneshot::Receiver<(LdapResult, Option<StructureTag>)>), Error=io::Error>> {
        let opts = match next_search_options(self) {
            Some(opts) => opts,
            None => SearchOptions::new(),
        };
        let req = Tag::Sequence(Sequence {
            id: 3,
            class: Application,
            inner: vec![
                   Tag::OctetString(OctetString {
                       inner: Vec::from(base.as_bytes()),
                       .. Default::default()
                   }),
                   Tag::Enumerated(Enumerated {
                       inner: scope as i64,
                       .. Default::default()
                   }),
                   Tag::Enumerated(Enumerated {
                       inner: opts.deref as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: opts.sizelimit as i64,
                       .. Default::default()
                   }),
                   Tag::Integer(Integer {
                       inner: opts.timelimit as i64,
                       .. Default::default()
                   }),
                   Tag::Boolean(Boolean {
                       inner: opts.typesonly,
                       .. Default::default()
                   }),
                   parse(filter).unwrap(),
                   Tag::Sequence(Sequence {
                       inner: attrs.into_iter().map(|s|
                            Tag::OctetString(OctetString { inner: Vec::from(s.as_ref()), ..Default::default() })).collect(),
                       .. Default::default()
                   })
            ],
        });

        let (tx_i, rx_i) = mpsc::unbounded::<SearchItem>();
        let (tx_r, rx_r) = oneshot::channel::<(LdapResult, Option<StructureTag>)>();
        let bundle = bundle(self);
        let fut = self.call(LdapOp::Multi(req, tx_i.clone())).and_then(move |res| {
            let id = match res {
                (Tag::Integer(Integer { id: _, class: _, inner }), _) => inner,
                _ => unimplemented!(),
            };
            Ok((SearchStream {
                id: id as RequestId,
                bundle: bundle,
                _tx_i: tx_i,
                rx_i: rx_i,
                tx_r: Some(tx_r),
                refs: Vec::new(),
            }, rx_r))
        });

        Box::new(fut)
    }
}
<|endoftext|>


<commit_before>use std::io::{Error, ErrorKind, Read, Write, Result};
use std::net::SocketAddr;
use std::sync::Arc;
use fibers::Spawn;
use fibers::net::{TcpListener, TcpStream};
use fibers::sync::oneshot::{Monitor, MonitorError};
use futures::{self, Future, IntoFuture, Poll, Stream, Async};
use futures::future::Either;
use handy_async::io::AsyncWrite;
use httparse;

use Method;
use {Header, Headers};
use headers::ContentLength;

pub struct HttpServerHandle {
    monitor: Monitor<(), Error>,
}
impl Future for HttpServerHandle {
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.monitor.poll().map_err(|e| {
            match e {
                MonitorError::Aborted => {
                    Error::new(ErrorKind::ConnectionAborted,
                               "The HTTP server exited unexpectedly")
                }
                MonitorError::Failed(e) => e,
            }
        })
    }
}
// impl stop,get_opts,set_opts,etc

pub trait HandleRequest: Clone + Send + 'static {
    type Future: Future<Item = ResponseBody, Error = ()> + Send;
    fn handle_request(self, req: Request) -> Self::Future;
    fn handle_error(self, server: SocketAddr, client: SocketAddr, error: Error) {
        error!("HTTP connection between {:?}(server) and {:?}(client) is disconnected: {}",
               client,
               server,
               error);

    }
}
impl<F, G> HandleRequest for Arc<Box<F>>
    where F: Fn(Request) -> G + Sync + Send + 'static,
          G: IntoFuture<Item = ResponseBody, Error = ()>,
          G::Future: Send
{
    type Future = G::Future;
    fn handle_request(self, req: Request) -> Self::Future {
        self(req).into_future()
    }
}

pub struct HttpServer<S> {
    addr: SocketAddr,
    spawner: S,
}
impl<S> HttpServer<S>
    where S: Spawn + Clone + Send + 'static
{
    pub fn new(addr: SocketAddr, spawner: S) -> Self {
        HttpServer {
            addr: addr,
            spawner: spawner,
        }
    }
    pub fn start_fn<F, G>(self, f: F) -> HttpServerHandle
        where F: Fn(Request) -> G + Sync + Send + 'static,
              G: IntoFuture<Item = ResponseBody, Error = ()>, // TODO: Error = Error
              G::Future: Send
    {
        self.start(Arc::new(Box::new(f)))
    }

    pub fn start<H>(self, handler: H) -> HttpServerHandle
        where H: HandleRequest
    {
        let HttpServer { addr, spawner } = self;
        let monitor = spawner.clone().spawn_monitor(TcpListener::bind(addr).and_then(|listener| {
            // TODO: support keep alive
            let server_addr = listener.local_addr().unwrap();
            listener.incoming().for_each(move |(client, client_addr)| {
                let handler = handler.clone();
                spawner.spawn(client.and_then(|socket| ReadHeader::new(socket))
                    .then(move |result| {
                        match result {
                            Err(e) => {
                                handler.handle_error(server_addr, client_addr, e);
                                Either::A(futures::failed(()))
                            }
                            Ok(req) => {
                                Either::B(handler.handle_request(req)
                                    .and_then(|res| {
                                        res.stream.async_flush().map(|_| ()).map_err(|_| ())
                                    }))
                            }
                        }
                    }));
                Ok(())
            })
        }));
        HttpServerHandle { monitor: monitor }
    }
}

pub struct ReadHeaderInner<'a> {
    reader: TcpStream,
    buf: Vec<u8>,
    offset: usize,
    headers: Vec<httparse::Header<'a>>,
}

pub struct ReadHeader<'a>(Option<ReadHeaderInner<'a>>);

impl<'a> ReadHeader<'a> {
    fn new(reader: TcpStream) -> Self {
        ReadHeader(Some(ReadHeaderInner {
            reader: reader,
            buf: vec![0; 1024],
            offset: 0,
            headers: vec![httparse::EMPTY_HEADER; 8],
        }))
    }
}
impl<'a> Future for ReadHeader<'a> {
    type Item = Request<'a>;
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut inner = self.0.take().expect("Cannot poll ReadHeader twice");
        if inner.offset == inner.buf.len() {
            let new_len = inner.offset * 2; // TODO: max size
            inner.buf.resize(new_len, 0);
        }
        match inner.reader.read(&mut inner.buf[inner.offset..]) {
            Err(e) => {
                if e.kind() == ErrorKind::WouldBlock {
                    self.0 = Some(inner);
                    Ok(Async::NotReady)
                } else {
                    Err(e)
                }
            }
            Ok(0) => Err(Error::new(ErrorKind::UnexpectedEof, "TODO")),
            Ok(read_size) => {
                inner.offset += read_size;
                loop {
                    let result = {
                        let buf = &inner.buf[0..inner.offset];
                        let buf = unsafe { &*(buf as *const _) as &'static _ };
                        let mut req = httparse::Request::new(&mut inner.headers);
                        match req.parse(buf) {
                            Err(httparse::Error::TooManyHeaders) => Err(true),
                            Err(e) => {
                                let e = Error::new(ErrorKind::InvalidData,
                                                   format!("HTTP parse failure: {}", e));
                                return Err(e);
                            }
                            Ok(httparse::Status::Partial) => Err(false),
                            Ok(httparse::Status::Complete(body_offset)) => {
                                let result = (Method::from_str(req.method.unwrap()),
                                              req.path.unwrap(),
                                              req.version.unwrap(),
                                              req.headers.len(),
                                              body_offset);
                                Ok(result)
                            }
                        }
                    };
                    match result {
                        Ok((method, path, version, header_count, body_offset)) => {
                            inner.headers.truncate(header_count);
                            let body =
                                RequestBodyStream::new(inner.reader,
                                                       inner.buf,
                                                       body_offset,
                                                       &Headers { headers: &inner.headers })?;
                            let req = Request {
                                method: method,
                                path: path,
                                version: version,
                                headers: inner.headers,
                                body: body,
                            };
                            return Ok(Async::Ready(req));
                        }
                        Err(false) => {
                            self.0 = Some(inner);
                            return self.poll();
                        }
                        Err(true) => {
                            // retry
                            let new_len = inner.headers.len() * 2; // TODO: size limit
                            inner.headers.resize(new_len, httparse::EMPTY_HEADER);
                        }
                    }
                }
            }
        }
    }
}

#[derive(Debug)]
pub struct RequestBodyStream<R: Read, B: AsRef<[u8]>> {
    stream: R,
    buf: B,
    offset: usize,
    remainings: u64,
}
impl<R: Read, B: AsRef<[u8]>> RequestBodyStream<R, B> {
    fn new(stream: R,
           buf: B,
           offset: usize,
           headers: &Headers)
           -> ::std::result::Result<Self, Error> {
        if headers.get_bytes("Transfer-Encoding").is_some() {
            unimplemented!()
        }
        let header = headers.get::<ContentLength>()?;
        Ok(RequestBodyStream {
            stream: stream,
            buf: buf,
            offset: offset,
            remainings: header.map(|h| h.len()).unwrap_or(0),
        })
    }
    fn unread_bytes(&self) -> Vec<u8> {
        Vec::from(&self.buf.as_ref()[self.offset..])
    }
}
impl<R: Read, B: AsRef<[u8]>> Read for RequestBodyStream<R, B> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        use std::cmp;
        let max_size = cmp::min(buf.len() as u64, self.remainings) as usize;
        if self.offset < self.buf.as_ref().len() {
            let size = cmp::min(max_size, self.buf.as_ref().len() - self.offset);
            buf[0..size].copy_from_slice(&self.buf.as_ref()[self.offset..self.offset + size]);
            self.offset += size;
            self.remainings -= size as u64;
            Ok(size)
        } else {
            let size = self.stream.read(&mut buf[0..max_size])?;
            self.remainings -= size as u64;
            Ok(size)
        }
    }
}

#[derive(Debug)]
pub struct Request<'a> {
    method: Method<'a>,
    path: &'a str,
    version: u8,
    headers: Vec<httparse::Header<'a>>,
    body: RequestBodyStream<TcpStream, Vec<u8>>,
}
impl<'a> Request<'a> {
    pub fn method(&self) -> &Method {
        &self.method
    }
    pub fn path(&self) -> &str {
        &self.path
    }
    pub fn version(&self) -> u8 {
        self.version
    }
    pub fn headers(&self) -> Headers {
        Headers { headers: &self.headers }
    }
    pub fn into_response(self, status_code: u16, status_reason: &'static str) -> Response {
        let unread = self.body.unread_bytes();
        let mut buf = Vec::with_capacity(1024);
        write!(buf,
               "HTTP/1.{} {} {}\r\n",
               self.version,
               status_code,
               status_reason)
            .unwrap();
        Response {
            pre_body_buf: buf,
            stream: self.body.stream,
            unread: unread,
        }
    }
}
impl<'a> Read for Request<'a> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.body.read(buf)
    }
}

pub struct Response {
    pre_body_buf: Vec<u8>,
    stream: TcpStream,
    unread: Vec<u8>,
}
impl Response {
    pub fn add_header<H: Header>(&mut self, header: &H) -> &mut Self {
        header.write(&mut self.pre_body_buf);
        self.pre_body_buf.extend_from_slice(b"\r\n");
        self
    }
    pub fn add_raw_header(&mut self, key: &str, value: &[u8]) {
        self.pre_body_buf.extend_from_slice(key.as_bytes());
        self.pre_body_buf.extend_from_slice(value);
        self.pre_body_buf.extend_from_slice(b"\r\n");
    }
    // TODO: into_body_stream
    pub fn into_body(mut self) -> ResponseBody {
        self.pre_body_buf.extend_from_slice(b"\r\n");
        ResponseBody {
            pre_body_buf: self.pre_body_buf,
            pre_body_offset: 0,
            stream: self.stream,
            unread: self.unread,
        }
    }
    pub fn write_body_bytes<B: AsRef<[u8]>>(self, body: B) -> WriteBodyBytes<B> {
        use handy_async::io::AsyncWrite;
        WriteBodyBytes(self.into_body().async_write_all(body))
    }
}

use handy_async::io::futures::WriteAll;
pub struct WriteBodyBytes<B>(WriteAll<ResponseBody, B>);
impl<B: AsRef<[u8]>> Future for WriteBodyBytes<B> {
    type Item = ResponseBody;
    type Error = ();
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        Ok(self.0.poll().map_err(|_| ())?.map(|(s, _)| s))
    }
}

pub struct ResponseBody {
    pre_body_buf: Vec<u8>,
    pre_body_offset: usize,
    stream: TcpStream,
    unread: Vec<u8>,
}
impl Write for ResponseBody {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        if self.pre_body_offset < self.pre_body_buf.len() {
            let size = self.stream.write(&self.pre_body_buf[self.pre_body_offset..])?;
            if size == 0 {
                Err(Error::new(ErrorKind::UnexpectedEof, "TODO"))
            } else {
                self.pre_body_offset += size;
                self.write(buf)
            }
        } else {
            self.stream.write(buf)
        }
    }
    fn flush(&mut self) -> Result<()> {
        if self.pre_body_offset < self.pre_body_buf.len() {
            let size = self.stream.write(&self.pre_body_buf[self.pre_body_offset..])?;
            if size == 0 {
                Err(Error::new(ErrorKind::UnexpectedEof, "TODO"))
            } else {
                self.pre_body_offset += size;
                self.flush()
            }
        } else {
            self.stream.flush()
        }
    }
}
<commit_msg>Small improvements<commit_after>use std::fmt;
use std::io::{Error, ErrorKind, Read, Write, Result};
use std::net::SocketAddr;
use std::sync::Arc;
use fibers::Spawn;
use fibers::net::{TcpListener, TcpStream};
use fibers::sync::oneshot::{Monitor, MonitorError};
use futures::{self, Future, IntoFuture, Poll, Stream, Async};
use futures::BoxFuture;
use futures::future::Either;
use handy_async::io::AsyncWrite;
use httparse;

use Method;
use {Header, Headers};
use headers::ContentLength;

pub struct HttpServerHandle {
    pub monitor: Monitor<(), Error>,
}
impl Future for HttpServerHandle {
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.monitor.poll().map_err(|e| {
            match e {
                MonitorError::Aborted => {
                    Error::new(ErrorKind::ConnectionAborted,
                               "The HTTP server exited unexpectedly")
                }
                MonitorError::Failed(e) => e,
            }
        })
    }
}
// impl stop,get_opts,set_opts,etc

pub trait HandleRequest: Clone + Send + 'static {
    type Future: Future<Item = ResponseBody, Error = ()> + Send;
    fn handle_request(self, req: Request<'static>) -> Self::Future;
    fn handle_error(self, server: SocketAddr, client: SocketAddr, error: Error) {
        error!("HTTP connection between {:?}(server) and {:?}(client) is disconnected: {}",
               client,
               server,
               error);

    }
}
impl<F, G> HandleRequest for Arc<Box<F>>
    where F: Fn(Request<'static>) -> G + Sync + Send + 'static,
          G: IntoFuture<Item = ResponseBody, Error = ()>,
          G::Future: Send
{
    type Future = G::Future;
    fn handle_request(self, req: Request<'static>) -> Self::Future {
        self(req).into_future()
    }
}

pub struct HttpServer<S> {
    addr: SocketAddr,
    spawner: S,
}
impl<S> HttpServer<S>
    where S: Spawn + Clone + Send + 'static
{
    pub fn new(addr: SocketAddr, spawner: S) -> Self {
        HttpServer {
            addr: addr,
            spawner: spawner,
        }
    }
    pub fn start_fn<F, G>(self, f: F) -> HttpServerHandle
        where F: Fn(Request) -> G + Sync + Send + 'static,
              G: IntoFuture<Item = ResponseBody, Error = ()>, // TODO: Error = Error
              G::Future: Send
    {
        self.start(Arc::new(Box::new(f)))
    }

    pub fn start<H>(self, handler: H) -> HttpServerHandle
        where H: HandleRequest
    {
        let HttpServer { addr, spawner } = self;
        let monitor = spawner.clone().spawn_monitor(TcpListener::bind(addr).and_then(|listener| {
            // TODO: support keep alive
            let server_addr = listener.local_addr().unwrap();
            listener.incoming().for_each(move |(client, client_addr)| {
                let handler = handler.clone();
                spawner.spawn(client.and_then(|socket| ReadHeader::new(socket))
                    .then(move |result| {
                        match result {
                            Err(e) => {
                                handler.handle_error(server_addr, client_addr, e);
                                Either::A(futures::failed(()))
                            }
                            Ok(req) => {
                                Either::B(handler.handle_request(req)
                                    .and_then(|res| {
                                        res.stream.async_flush().map(|_| ()).map_err(|_| ())
                                    }))
                            }
                        }
                    }));
                Ok(())
            })
        }));
        HttpServerHandle { monitor: monitor }
    }
}

pub struct ReadHeaderInner<'a> {
    reader: TcpStream,
    buf: Vec<u8>,
    offset: usize,
    headers: Vec<httparse::Header<'a>>,
}

pub struct ReadHeader<'a>(Option<ReadHeaderInner<'a>>);

impl<'a> ReadHeader<'a> {
    fn new(reader: TcpStream) -> Self {
        ReadHeader(Some(ReadHeaderInner {
            reader: reader,
            buf: vec![0; 1024],
            offset: 0,
            headers: vec![httparse::EMPTY_HEADER; 8],
        }))
    }
}
impl<'a> Future for ReadHeader<'a> {
    type Item = Request<'a>;
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut inner = self.0.take().expect("Cannot poll ReadHeader twice");
        if inner.offset == inner.buf.len() {
            let new_len = inner.offset * 2; // TODO: max size
            inner.buf.resize(new_len, 0);
        }
        match inner.reader.read(&mut inner.buf[inner.offset..]) {
            Err(e) => {
                if e.kind() == ErrorKind::WouldBlock {
                    self.0 = Some(inner);
                    Ok(Async::NotReady)
                } else {
                    Err(e)
                }
            }
            Ok(0) => Err(Error::new(ErrorKind::UnexpectedEof, "TODO")),
            Ok(read_size) => {
                inner.offset += read_size;
                loop {
                    let result = {
                        let buf = &inner.buf[0..inner.offset];
                        let buf = unsafe { &*(buf as *const _) as &'static _ };
                        let mut req = httparse::Request::new(&mut inner.headers);
                        match req.parse(buf) {
                            Err(httparse::Error::TooManyHeaders) => Err(true),
                            Err(e) => {
                                let e = Error::new(ErrorKind::InvalidData,
                                                   format!("HTTP parse failure: {}", e));
                                return Err(e);
                            }
                            Ok(httparse::Status::Partial) => Err(false),
                            Ok(httparse::Status::Complete(body_offset)) => {
                                let result = (Method::from_str(req.method.unwrap()),
                                              req.path.unwrap(),
                                              req.version.unwrap(),
                                              req.headers.len(),
                                              body_offset);
                                Ok(result)
                            }
                        }
                    };
                    match result {
                        Ok((method, path, version, header_count, body_offset)) => {
                            inner.headers.truncate(header_count);
                            let body =
                                RequestBodyStream::new(inner.reader,
                                                       inner.buf,
                                                       body_offset,
                                                       &Headers { headers: &inner.headers })?;
                            let req = Request {
                                method: method,
                                path: path,
                                version: version,
                                headers: inner.headers,
                                body: body,
                            };
                            return Ok(Async::Ready(req));
                        }
                        Err(false) => {
                            self.0 = Some(inner);
                            return self.poll();
                        }
                        Err(true) => {
                            // retry
                            let new_len = inner.headers.len() * 2; // TODO: size limit
                            inner.headers.resize(new_len, httparse::EMPTY_HEADER);
                        }
                    }
                }
            }
        }
    }
}

#[derive(Debug)]
pub struct RequestBodyStream<R: Read, B: AsRef<[u8]>> {
    stream: R,
    buf: B,
    offset: usize,
    remainings: u64,
}
impl<R: Read, B: AsRef<[u8]>> RequestBodyStream<R, B> {
    fn new(stream: R,
           buf: B,
           offset: usize,
           headers: &Headers)
           -> ::std::result::Result<Self, Error> {
        if headers.get_bytes("Transfer-Encoding").is_some() {
            unimplemented!()
        }
        let header = headers.get::<ContentLength>()?;
        Ok(RequestBodyStream {
            stream: stream,
            buf: buf,
            offset: offset,
            remainings: header.map(|h| h.len()).unwrap_or(0),
        })
    }
    fn unread_bytes(&self) -> Vec<u8> {
        Vec::from(&self.buf.as_ref()[self.offset..])
    }
}
impl<R: Read, B: AsRef<[u8]>> Read for RequestBodyStream<R, B> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        use std::cmp;
        let max_size = cmp::min(buf.len() as u64, self.remainings) as usize;
        if self.offset < self.buf.as_ref().len() {
            let size = cmp::min(max_size, self.buf.as_ref().len() - self.offset);
            buf[0..size].copy_from_slice(&self.buf.as_ref()[self.offset..self.offset + size]);
            self.offset += size;
            self.remainings -= size as u64;
            Ok(size)
        } else {
            let size = self.stream.read(&mut buf[0..max_size])?;
            self.remainings -= size as u64;
            Ok(size)
        }
    }
}

pub type ReadBodyBytes<'a> = BoxFuture<(Request<'a>, Vec<u8>), (Request<'a>, Error)>;
// pub struct ReadBodyBytes<'a>(Request<'a>);
// impl<'a> Future for ReadBodyBytes<'a> {
//     type Item = (Request<'a>, Vec<u8>);
//     type Error = (Request<'a>, Error);
//     fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
//         panic!()
//     }
// }

pub struct Request<'a> {
    method: Method<'a>,
    path: &'a str,
    version: u8,
    headers: Vec<httparse::Header<'a>>,
    body: RequestBodyStream<TcpStream, Vec<u8>>,
}
impl<'a> fmt::Debug for Request<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Request {{ method: {:?}, path: {:?}, version: {:?}, headers: {{",
               self.method,
               self.path,
               self.version)?;
        let mut is_first = true;
        for h in self.headers.iter() {
            use std::str;
            if !is_first {
                write!(f, ", ")?;
            }
            is_first = false;
            if let Ok(value) = str::from_utf8(h.value) {
                write!(f, "{:?} => {:?}", h.name, value)?;
            } else {
                write!(f, "{:?} => {:?}", h.name, h.value)?;
            }
        }
        write!(f, "}}, body: _ }}")
    }
}
impl Request<'static> {
    pub fn read_body_bytes(self) -> ReadBodyBytes<'static> {
        use handy_async::io::ReadFrom;
        use handy_async::pattern::read::All;
        // TODO: Handle chunked-stream
        // TODO: Limit max size
        if let Some(length) = self.headers().get::<ContentLength>().unwrap() {
            let buf = vec![0; length.0 as usize];
            buf.read_from(self).map_err(|e| e.unwrap()).boxed()
        } else {
            All.read_from(self).map_err(|e| e.unwrap()).boxed()
        }
    }
}
impl<'a> Request<'a> {
    pub fn method(&self) -> &Method {
        &self.method
    }
    pub fn path(&self) -> &str {
        &self.path
    }
    pub fn version(&self) -> u8 {
        self.version
    }
    pub fn headers(&self) -> Headers {
        Headers { headers: &self.headers }
    }
    pub fn into_response(self, status_code: u16, status_reason: &'static str) -> Response {
        let unread = self.body.unread_bytes();
        let mut buf = Vec::with_capacity(1024);
        write!(buf,
               "HTTP/1.{} {} {}\r\n",
               self.version,
               status_code,
               status_reason)
            .unwrap();
        Response {
            pre_body_buf: buf,
            stream: self.body.stream,
            unread: unread,
        }
    }
}
impl<'a> Read for Request<'a> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.body.read(buf)
    }
}

pub struct Response {
    pre_body_buf: Vec<u8>,
    stream: TcpStream,
    unread: Vec<u8>,
}
impl Response {
    pub fn add_header<H: Header>(&mut self, header: &H) -> &mut Self {
        header.write(&mut self.pre_body_buf);
        self.pre_body_buf.extend_from_slice(b"\r\n");
        self
    }
    pub fn add_raw_header(&mut self, key: &str, value: &[u8]) {
        self.pre_body_buf.extend_from_slice(key.as_bytes());
        self.pre_body_buf.extend_from_slice(": ".as_bytes());
        self.pre_body_buf.extend_from_slice(value);
        self.pre_body_buf.extend_from_slice(b"\r\n");
    }
    // TODO: into_body_stream
    pub fn into_body(mut self) -> ResponseBody {
        self.pre_body_buf.extend_from_slice(b"\r\n");
        ResponseBody {
            pre_body_buf: self.pre_body_buf,
            pre_body_offset: 0,
            stream: self.stream,
            unread: self.unread,
        }
    }
    pub fn write_body_bytes<B: AsRef<[u8]>>(self, body: B) -> WriteBodyBytes<B> {
        use handy_async::io::AsyncWrite;
        WriteBodyBytes(self.into_body().async_write_all(body))
    }
}

use handy_async::io::futures::WriteAll;
pub struct WriteBodyBytes<B>(WriteAll<ResponseBody, B>);
impl<B: AsRef<[u8]>> Future for WriteBodyBytes<B> {
    type Item = ResponseBody;
    type Error = ();
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        Ok(self.0.poll().map_err(|_| ())?.map(|(s, _)| s))
    }
}

#[allow(dead_code)]
pub struct ResponseBody {
    pre_body_buf: Vec<u8>,
    pre_body_offset: usize,
    stream: TcpStream,
    unread: Vec<u8>,
}
impl Write for ResponseBody {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        if self.pre_body_offset < self.pre_body_buf.len() {
            let size = self.stream.write(&self.pre_body_buf[self.pre_body_offset..])?;
            if size == 0 {
                Err(Error::new(ErrorKind::UnexpectedEof, "TODO"))
            } else {
                self.pre_body_offset += size;
                self.write(buf)
            }
        } else {
            self.stream.write(buf)
        }
    }
    fn flush(&mut self) -> Result<()> {
        if self.pre_body_offset < self.pre_body_buf.len() {
            let size = self.stream.write(&self.pre_body_buf[self.pre_body_offset..])?;
            if size == 0 {
                Err(Error::new(ErrorKind::UnexpectedEof, "TODO"))
            } else {
                self.pre_body_offset += size;
                self.flush()
            }
        } else {
            self.stream.flush()
        }
    }
}
<|endoftext|>


<commit_before>use serde_json::{self, Value};
use serde::ser::Serialize;

use std::convert::From;
use std::collections::HashMap;
use std::borrow::Cow;
use std::io::{self, BufRead, BufReader, Read, Write};

pub trait Interface {
    fn get_description(&self) -> &'static str;
    fn get_name(&self) -> &'static str;
    fn call(&self, &mut Call) -> io::Result<()>;
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Request {
    pub method: Cow<'static, str>,
    pub parameters: Option<Value>,
}

pub trait VarlinkReply {}

#[derive(Serialize, Deserialize)]
pub struct Reply {
    error: Option<Cow<'static, str>>,
    parameters: Option<Value>,
}

impl Reply {
    pub fn parameters(parameters: Value) -> Self {
        Reply {
            error: None,
            parameters: Some(parameters),
        }
    }

    pub fn error(name: Cow<'static, str>, parameters: Option<Value>) -> Self {
        Reply {
            error: Some(name),
            parameters,
        }
    }
}

impl<T> From<T> for Reply
where
    T: VarlinkReply,
    T: Serialize,
{
    fn from(a: T) -> Self {
        Reply::parameters(serde_json::to_value(a).unwrap())
    }
}

pub struct Call<'a> {
    writer: &'a mut Write,
    pub request: &'a Request,
}

impl<'a> Call<'a> {
    fn new(writer: &'a mut Write, request: &'a Request) -> Self {
        Call { writer, request }
    }

    fn reply_parameters(&mut self, parameters: Value) -> io::Result<()> {
        let reply = Reply::parameters(parameters);
        let mut buf = serde_json::to_vec(&reply)?;
        buf.push(0);
        self.writer.write_all(&mut buf)?;
        Ok(())
    }

    pub fn reply(&mut self, reply: Reply) -> io::Result<()> {
        let mut buf = serde_json::to_vec(&reply)?;
        buf.push(0);
        self.writer.write_all(&mut buf)?;
        Ok(())
    }
}

/*
# The requested interface was not found.
error InterfaceNotFound (interface: string)

# The requested method was not found
error MethodNotFound (method: string)

# The interface defines the requested method, but the service does not
# implement it.
error MethodNotImplemented (method: string)

# One of the passed parameters is invalid.
error InvalidParameter (parameter: string)
*/

#[derive(Debug)]
pub enum VarlinkError {
    InterfaceNotFound(Option<Cow<'static, str>>),
    MethodNotFound(Option<Cow<'static, str>>),
    MethodNotImplemented(Option<Cow<'static, str>>),
    InvalidParameter(Option<Cow<'static, str>>),
}

impl From<VarlinkError> for Reply {
    fn from(e: VarlinkError) -> Self {
        Reply {
            error: Some(match e {
                VarlinkError::MethodNotFound(_) => "org.varlink.service.MethodNotFound".into(),
                VarlinkError::InterfaceNotFound(_) => {
                    "org.varlink.service.InterfaceNotFound".into()
                }
                VarlinkError::MethodNotImplemented(_) => {
                    "org.varlink.service.MethodNotImplemented".into()
                }
                VarlinkError::InvalidParameter(_) => "org.varlink.service.InvalidParameter".into(),
            }),
            parameters: match e {
                VarlinkError::InterfaceNotFound(m) => match m {
                    Some(i) => Some(
                        serde_json::from_str(format!("{{ \"interface\" : \"{}\" }}", i).as_ref())
                            .unwrap(),
                    ),
                    None => None,
                },
                VarlinkError::MethodNotFound(m) => match m {
                    Some(me) => {
                        let method: String = me.into();
                        let n: usize = match method.rfind('.') {
                            None => 0,
                            Some(x) => x + 1,
                        };
                        let (_, method) = method.split_at(n);
                        let s = format!("{{  \"method\" : \"{}\" }}", method);
                        Some(serde_json::from_str(s.as_ref()).unwrap())
                    }
                    None => None,
                },
                VarlinkError::MethodNotImplemented(m) => match m {
                    Some(me) => {
                        let method: String = me.into();
                        let n: usize = match method.rfind('.') {
                            None => 0,
                            Some(x) => x + 1,
                        };
                        let (_, method) = method.split_at(n);
                        let s = format!("{{  \"method\" : \"{}\" }}", method);
                        Some(serde_json::from_str(s.as_ref()).unwrap())
                    }
                    None => None,
                },
                VarlinkError::InvalidParameter(m) => match m {
                    Some(i) => Some(
                        serde_json::from_str(format!("{{ \"parameter\" : \"{}\" }}", i).as_ref())
                            .unwrap(),
                    ),
                    None => None,
                },
            },
        }
    }
}

impl From<serde_json::Error> for Reply {
    fn from(_e: serde_json::Error) -> Self {
        VarlinkError::InvalidParameter(Some(_e.to_string().into())).into()
    }
}

#[derive(Deserialize)]
struct GetInterfaceArgs {
    interface: Cow<'static, str>,
}

#[derive(Serialize, Deserialize, Default)]
struct Property {
    key: Cow<'static, str>,
    value: Cow<'static, str>,
}

#[derive(Serialize, Deserialize, Default)]
struct ServiceInfo {
    vendor: Cow<'static, str>,
    product: Cow<'static, str>,
    version: Cow<'static, str>,
    url: Cow<'static, str>,
    interfaces: Vec<Cow<'static, str>>,
}

pub struct VarlinkService {
    info: ServiceInfo,
    ifaces: HashMap<Cow<'static, str>, Box<Interface>>,
}

impl Interface for VarlinkService {
    fn get_description(&self) -> &'static str {
        r#"
# The Varlink Service Interface is provided by every varlink service. It
# describes the service and the interfaces it implements.
interface org.varlink.service

# Get a list of all the interfaces a service provides and information
# about the implementation.
method GetInfo() -> (
  vendor: string,
  product: string,
  version: string,
  url: string,
  interfaces: string[]
)

# Get the description of an interface that is implemented by this service.
method GetInterfaceDescription(interface: string) -> (description: string)

# The requested interface was not found.
error InterfaceNotFound (interface: string)

# The requested method was not found
error MethodNotFound (method: string)

# The interface defines the requested method, but the service does not
# implement it.
error MethodNotImplemented (method: string)

# One of the passed parameters is invalid.
error InvalidParameter (parameter: string)
	"#
    }

    fn get_name(&self) -> &'static str {
        "org.varlink.service"
    }

    fn call(&self, call: &mut Call) -> io::Result<()> {
        match call.request.method.as_ref() {
            "org.varlink.service.GetInfo" => {
                return call.reply_parameters(serde_json::to_value(&self.info)?);
            }
            "org.varlink.service.GetInterfaceDescription" => {
                if call.request.parameters == None {
                    return call.reply(VarlinkError::InvalidParameter(None).into());
                }
                if let Some(val) = call.request.parameters.clone() {
                    let args: GetInterfaceArgs = serde_json::from_value(val)?;
                    match args.interface.as_ref() {
                        "org.varlink.service" => {
                            return call.reply_parameters(
                                json!({"description": self.get_description()}),
                            );
                        }
                        key => {
                            if self.ifaces.contains_key(key) {
                                return call.reply_parameters(
                                    json!({"description": self.ifaces[key].get_description()}),
                                );
                            } else {
                                return call.reply(
                                    VarlinkError::InvalidParameter(Some("interface".into())).into(),
                                );
                            }
                        }
                    }
                } else {
                    return call.reply(
                        VarlinkError::InvalidParameter(Some("interface".into())).into(),
                    );
                }
            }
            _ => {
                let method: String = call.request.method.clone().into();
                let n: usize = match method.rfind('.') {
                    None => 0,
                    Some(x) => x + 1,
                };
                let m = String::from(&method[n..]);
                return call.reply(VarlinkError::MethodNotFound(Some(m.clone().into())).into());
            }
        }
    }
}

impl VarlinkService {
    pub fn new(
        vendor: &str,
        product: &str,
        version: &str,
        url: &str,
        ifaces: Vec<Box<Interface>>,
    ) -> Self {
        let mut ifhashmap = HashMap::<Cow<'static, str>, Box<Interface>>::new();
        for i in ifaces {
            ifhashmap.insert(i.get_name().into(), i);
        }
        let mut ifnames: Vec<Cow<'static, str>> = Vec::new();
        ifnames.push("org.varlink.service".into());
        ifnames.extend(
            ifhashmap
                .keys()
                .map(|i| Cow::<'static, str>::from(i.clone())),
        );
        VarlinkService {
            info: ServiceInfo {
                vendor: String::from(vendor).into(),
                product: String::from(product).into(),
                version: String::from(version).into(),
                url: String::from(url).into(),
                interfaces: ifnames,
                ..Default::default()
            },
            ifaces: ifhashmap,
        }
    }

    fn call(&self, call: &mut Call) -> io::Result<()> {
        println!("Request: {}", serde_json::to_string(&call.request).unwrap());
        let n: usize = match call.request.method.rfind('.') {
            None => {
                let method = call.request.method.clone();
                return call.reply(VarlinkError::InterfaceNotFound(Some(method.into())).into());
            }
            Some(x) => x,
        };
        let iface = String::from(&call.request.method[..n]);

        match iface.as_ref() {
            "org.varlink.service" => return self::Interface::call(self, call),
            key => {
                if self.ifaces.contains_key(key) {
                    return self.ifaces[key].call(call);
                } else {
                    return call.reply(
                        VarlinkError::InterfaceNotFound(Some(iface.clone().into())).into(),
                    );
                }
            }
        }
    }

    pub fn handle(&self, reader: &mut Read, writer: &mut Write) -> io::Result<()> {
        let mut bufreader = BufReader::new(reader);
        loop {
            let mut buf = Vec::new();
            let read_bytes = bufreader.read_until(b'\0', &mut buf).unwrap();
            if read_bytes > 0 {
                buf.pop();
                let req: Request = serde_json::from_slice(&buf)?;
                self.call(&mut Call::new(writer, &req))?;
            } else {
                break;
            }
        }
        Ok(())
    }
}
<commit_msg>flush after write<commit_after>use serde_json::{self, Value};
use serde::ser::Serialize;

use std::convert::From;
use std::collections::HashMap;
use std::borrow::Cow;
use std::io::{self, BufRead, BufReader, Read, Write};

pub trait Interface {
    fn get_description(&self) -> &'static str;
    fn get_name(&self) -> &'static str;
    fn call(&self, &mut Call) -> io::Result<()>;
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Request {
    pub method: Cow<'static, str>,
    pub parameters: Option<Value>,
}

pub trait VarlinkReply {}

#[derive(Serialize, Deserialize)]
pub struct Reply {
    error: Option<Cow<'static, str>>,
    parameters: Option<Value>,
}

impl Reply {
    pub fn parameters(parameters: Value) -> Self {
        Reply {
            error: None,
            parameters: Some(parameters),
        }
    }

    pub fn error(name: Cow<'static, str>, parameters: Option<Value>) -> Self {
        Reply {
            error: Some(name),
            parameters,
        }
    }
}

impl<T> From<T> for Reply
where
    T: VarlinkReply,
    T: Serialize,
{
    fn from(a: T) -> Self {
        Reply::parameters(serde_json::to_value(a).unwrap())
    }
}

pub struct Call<'a> {
    writer: &'a mut Write,
    pub request: &'a Request,
}

impl<'a> Call<'a> {
    fn new(writer: &'a mut Write, request: &'a Request) -> Self {
        Call { writer, request }
    }

    fn reply_parameters(&mut self, parameters: Value) -> io::Result<()> {
        let reply = Reply::parameters(parameters);
        let mut buf = serde_json::to_vec(&reply)?;
        buf.push(0);
        self.writer.write_all(&mut buf)?;
        self.writer.flush()?;
        Ok(())
    }

    pub fn reply(&mut self, reply: Reply) -> io::Result<()> {
        let mut buf = serde_json::to_vec(&reply)?;
        buf.push(0);
        self.writer.write_all(&mut buf)?;
        self.writer.flush()?;
        Ok(())
    }
}

/*
# The requested interface was not found.
error InterfaceNotFound (interface: string)

# The requested method was not found
error MethodNotFound (method: string)

# The interface defines the requested method, but the service does not
# implement it.
error MethodNotImplemented (method: string)

# One of the passed parameters is invalid.
error InvalidParameter (parameter: string)
*/

#[derive(Debug)]
pub enum VarlinkError {
    InterfaceNotFound(Option<Cow<'static, str>>),
    MethodNotFound(Option<Cow<'static, str>>),
    MethodNotImplemented(Option<Cow<'static, str>>),
    InvalidParameter(Option<Cow<'static, str>>),
}

impl From<VarlinkError> for Reply {
    fn from(e: VarlinkError) -> Self {
        Reply {
            error: Some(match e {
                VarlinkError::MethodNotFound(_) => "org.varlink.service.MethodNotFound".into(),
                VarlinkError::InterfaceNotFound(_) => {
                    "org.varlink.service.InterfaceNotFound".into()
                }
                VarlinkError::MethodNotImplemented(_) => {
                    "org.varlink.service.MethodNotImplemented".into()
                }
                VarlinkError::InvalidParameter(_) => "org.varlink.service.InvalidParameter".into(),
            }),
            parameters: match e {
                VarlinkError::InterfaceNotFound(m) => match m {
                    Some(i) => Some(
                        serde_json::from_str(format!("{{ \"interface\" : \"{}\" }}", i).as_ref())
                            .unwrap(),
                    ),
                    None => None,
                },
                VarlinkError::MethodNotFound(m) => match m {
                    Some(me) => {
                        let method: String = me.into();
                        let n: usize = match method.rfind('.') {
                            None => 0,
                            Some(x) => x + 1,
                        };
                        let (_, method) = method.split_at(n);
                        let s = format!("{{  \"method\" : \"{}\" }}", method);
                        Some(serde_json::from_str(s.as_ref()).unwrap())
                    }
                    None => None,
                },
                VarlinkError::MethodNotImplemented(m) => match m {
                    Some(me) => {
                        let method: String = me.into();
                        let n: usize = match method.rfind('.') {
                            None => 0,
                            Some(x) => x + 1,
                        };
                        let (_, method) = method.split_at(n);
                        let s = format!("{{  \"method\" : \"{}\" }}", method);
                        Some(serde_json::from_str(s.as_ref()).unwrap())
                    }
                    None => None,
                },
                VarlinkError::InvalidParameter(m) => match m {
                    Some(i) => Some(
                        serde_json::from_str(format!("{{ \"parameter\" : \"{}\" }}", i).as_ref())
                            .unwrap(),
                    ),
                    None => None,
                },
            },
        }
    }
}

/*
impl From<serde_json::Error> for Reply {
    fn from(_e: serde_json::Error) -> Self {
        VarlinkError::InvalidParameter(Some(_e.to_string().into())).into()
    }
}
*/

#[derive(Deserialize)]
struct GetInterfaceArgs {
    interface: Cow<'static, str>,
}

#[derive(Serialize, Deserialize, Default)]
struct Property {
    key: Cow<'static, str>,
    value: Cow<'static, str>,
}

#[derive(Serialize, Deserialize, Default)]
struct ServiceInfo {
    vendor: Cow<'static, str>,
    product: Cow<'static, str>,
    version: Cow<'static, str>,
    url: Cow<'static, str>,
    interfaces: Vec<Cow<'static, str>>,
}

pub struct VarlinkService {
    info: ServiceInfo,
    ifaces: HashMap<Cow<'static, str>, Box<Interface>>,
}

impl Interface for VarlinkService {
    fn get_description(&self) -> &'static str {
        r#"
# The Varlink Service Interface is provided by every varlink service. It
# describes the service and the interfaces it implements.
interface org.varlink.service

# Get a list of all the interfaces a service provides and information
# about the implementation.
method GetInfo() -> (
  vendor: string,
  product: string,
  version: string,
  url: string,
  interfaces: string[]
)

# Get the description of an interface that is implemented by this service.
method GetInterfaceDescription(interface: string) -> (description: string)

# The requested interface was not found.
error InterfaceNotFound (interface: string)

# The requested method was not found
error MethodNotFound (method: string)

# The interface defines the requested method, but the service does not
# implement it.
error MethodNotImplemented (method: string)

# One of the passed parameters is invalid.
error InvalidParameter (parameter: string)
	"#
    }

    fn get_name(&self) -> &'static str {
        "org.varlink.service"
    }

    fn call(&self, call: &mut Call) -> io::Result<()> {
        match call.request.method.as_ref() {
            "org.varlink.service.GetInfo" => {
                return call.reply_parameters(serde_json::to_value(&self.info)?);
            }
            "org.varlink.service.GetInterfaceDescription" => {
                if call.request.parameters == None {
                    return call.reply(VarlinkError::InvalidParameter(None).into());
                }
                if let Some(val) = call.request.parameters.clone() {
                    let args: GetInterfaceArgs = serde_json::from_value(val)?;
                    match args.interface.as_ref() {
                        "org.varlink.service" => {
                            return call.reply_parameters(
                                json!({"description": self.get_description()}),
                            );
                        }
                        key => {
                            if self.ifaces.contains_key(key) {
                                return call.reply_parameters(
                                    json!({"description": self.ifaces[key].get_description()}),
                                );
                            } else {
                                return call.reply(
                                    VarlinkError::InvalidParameter(Some("interface".into())).into(),
                                );
                            }
                        }
                    }
                } else {
                    return call.reply(
                        VarlinkError::InvalidParameter(Some("interface".into())).into(),
                    );
                }
            }
            _ => {
                let method: String = call.request.method.clone().into();
                let n: usize = match method.rfind('.') {
                    None => 0,
                    Some(x) => x + 1,
                };
                let m = String::from(&method[n..]);
                return call.reply(VarlinkError::MethodNotFound(Some(m.clone().into())).into());
            }
        }
    }
}

impl VarlinkService {
    pub fn new(
        vendor: &str,
        product: &str,
        version: &str,
        url: &str,
        ifaces: Vec<Box<Interface>>,
    ) -> Self {
        let mut ifhashmap = HashMap::<Cow<'static, str>, Box<Interface>>::new();
        for i in ifaces {
            ifhashmap.insert(i.get_name().into(), i);
        }
        let mut ifnames: Vec<Cow<'static, str>> = Vec::new();
        ifnames.push("org.varlink.service".into());
        ifnames.extend(
            ifhashmap
                .keys()
                .map(|i| Cow::<'static, str>::from(i.clone())),
        );
        VarlinkService {
            info: ServiceInfo {
                vendor: String::from(vendor).into(),
                product: String::from(product).into(),
                version: String::from(version).into(),
                url: String::from(url).into(),
                interfaces: ifnames,
                ..Default::default()
            },
            ifaces: ifhashmap,
        }
    }

    fn call(&self, call: &mut Call) -> io::Result<()> {
        println!("Request: {}", serde_json::to_string(&call.request).unwrap());
        let n: usize = match call.request.method.rfind('.') {
            None => {
                let method = call.request.method.clone();
                return call.reply(VarlinkError::InterfaceNotFound(Some(method.into())).into());
            }
            Some(x) => x,
        };
        let iface = String::from(&call.request.method[..n]);

        match iface.as_ref() {
            "org.varlink.service" => return self::Interface::call(self, call),
            key => {
                if self.ifaces.contains_key(key) {
                    return self.ifaces[key].call(call);
                } else {
                    return call.reply(
                        VarlinkError::InterfaceNotFound(Some(iface.clone().into())).into(),
                    );
                }
            }
        }
    }

    pub fn handle(&self, reader: &mut Read, writer: &mut Write) -> io::Result<()> {
        let mut bufreader = BufReader::new(reader);
        loop {
            let mut buf = Vec::new();
            let read_bytes = bufreader.read_until(b'\0', &mut buf).unwrap();
            if read_bytes > 0 {
                buf.pop();
                let req: Request = serde_json::from_slice(&buf)?;
                self.call(&mut Call::new(writer, &req))?;
            } else {
                break;
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        if let &Some(ref o) = init { check_expr(cx, o, bindings) }
        check_pat(cx, pat, init, span, bindings);
    }
}

fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span,
        bindings: &mut Vec<Name>) where T: Deref<Target=Expr> {
    //TODO: match more stuff / destructuring
    match pat.node {
        PatIdent(_, ref ident, ref inner) => {
            let name = ident.node.name;
            if pat_is_binding(&cx.tcx.def_map, pat) {
                if bindings.contains(&name) {
                    lint_shadow(cx, name, span, pat.span, init);
                }
                bindings.push(name);
            }
            if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); }
        },
        //PatEnum(Path, Option<Vec<P<Pat>>>),
        //PatQPath(QSelf, Path),
        //PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
        //PatTup(Vec<P<Pat>>),
        PatBox(ref inner) => {
            if let Some(ref initp) = *init {
                match initp.node {
                    ExprBox(_, ref inner_init) =>
                        check_pat(cx, inner, &Some(&**inner_init), span, bindings),
                    //TODO: ExprCall on Box::new
                    _ => check_pat(cx, inner, init, span, bindings),
                }
            } else {
                check_pat(cx, inner, init, span, bindings);
            }
        },
        //PatRegion(P<Pat>, Mutability),
        //PatRange(P<Expr>, P<Expr>),
        //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
        _ => (),
    }
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        //ExprCall
        //ExprMethodCall
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) => {
            check_expr(cx, init, bindings);
            for ref arm in arms {
                for ref pat in &arm.pats {
                    check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
                    //TODO: This is ugly, but needed to get the right type
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &arm.body, bindings);
            }
        },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    !path.global && path.segments.len() == 1 &&
        path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<commit_msg>shadowing detection<commit_after>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use rustc::middle::def::Def::{DefVariant, DefStruct};

use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        if let &Some(ref o) = init { check_expr(cx, o, bindings) }
        check_pat(cx, pat, init, span, bindings);
    }
}

fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span,
        bindings: &mut Vec<Name>) where T: Deref<Target=Expr> {
    //TODO: match more stuff / destructuring
    match pat.node {
        PatIdent(_, ref ident, ref inner) => {
            let name = ident.node.name;
            if pat_is_binding(&cx.tcx.def_map, pat) {
                if bindings.contains(&name) {
                    lint_shadow(cx, name, span, pat.span, init);
                }
                bindings.push(name);
            }
            if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); }
        },
        //PatEnum(Path, Option<Vec<P<Pat>>>),
        //PatQPath(QSelf, Path),
        //PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
        //PatTup(Vec<P<Pat>>),
        PatBox(ref inner) => {
            if let Some(ref initp) = *init {
                match initp.node {
                    ExprBox(_, ref inner_init) =>
                        check_pat(cx, inner, &Some(&**inner_init), span, bindings),
                    //TODO: ExprCall on Box::new
                    _ => check_pat(cx, inner, init, span, bindings),
                }
            } else {
                check_pat(cx, inner, init, span, bindings);
            }
        },
        //PatRegion(P<Pat>, Mutability),
        //PatRange(P<Expr>, P<Expr>),
        //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
        _ => (),
    }
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        //ExprCall
        //ExprMethodCall
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) => {
            check_expr(cx, init, bindings);
            for ref arm in arms {
                for ref pat in &arm.pats {
                    check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
                    //TODO: This is ugly, but needed to get the right type
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &arm.body, bindings);
            }
        },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    !path.global && path.segments.len() == 1 &&
        path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<|endoftext|>