<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        //let mut statu

        {
            let statuses = try!(self.cp.get_many(&mut self.statuses[..], timeout));
            for status in statuses {
                let token = status.token();
                let overlapped = status.overlapped();
                let bytes_transferred = status.bytes_transferred();
                let handle = Handle { val: token };
                if self.observers[handle].read_overlapped == overlapped {
                    match self.observers[handle].read_fulfiller.take() {
                        None => (),
                        Some(f) => f.fulfill(bytes_transferred),
                    }
                }
                if self.observers[handle].write_overlapped == overlapped {
                    match self.observers[handle].write_fulfiller.take() {
                        None => (),
                        Some(f) => f.fulfill(bytes_transferred),
                    }
                }

            }
        }
        Ok(())
    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };
        let mut overlapped = ::miow::Overlapped::zero();
        let (stream, ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut overlapped))
        };

        if ready {
            Promise::ok(pry!(SocketStreamInner::new(self.reactor.clone(), stream)))
        } else {
            unimplemented!()
        }
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            println!("accepted!");
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                ->Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(buf.as_mut(), read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |n| {
            println!("read transferred this many bytes: {}", n);
            Ok((buf, n as usize))
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             mut already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(buf.as_ref(), write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().map(move |n| {
            println!("write transferred this many bytes: {}", n);
            Ok(buf)
        });

        result
    }
}
<commit_msg>loop in read/write<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        //let mut statu

        {
            let statuses = try!(self.cp.get_many(&mut self.statuses[..], timeout));
            for status in statuses {
                let token = status.token();
                let overlapped = status.overlapped();
                let bytes_transferred = status.bytes_transferred();
                let handle = Handle { val: token };
                if self.observers[handle].read_overlapped == overlapped {
                    match self.observers[handle].read_fulfiller.take() {
                        None => (),
                        Some(f) => f.fulfill(bytes_transferred),
                    }
                }
                if self.observers[handle].write_overlapped == overlapped {
                    match self.observers[handle].write_fulfiller.take() {
                        None => (),
                        Some(f) => f.fulfill(bytes_transferred),
                    }
                }

            }
        }
        Ok(())
    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };
        let mut overlapped = ::miow::Overlapped::zero();
        let (stream, ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut overlapped))
        };

        if ready {
            Promise::ok(pry!(SocketStreamInner::new(self.reactor.clone(), stream)))
        } else {
            unimplemented!()
        }
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            println!("accepted!");
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_read >= min_bytes {
            return Promise::ok((buf, already_read));
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| {
            println!("read transferred this many bytes: {}", n);
            let total_read = n as usize + already_read;
            if n == 0 {
                println!("EOF");
                Promise::ok((buf, total_read))
            } else {
                SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes)
            }
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_written == buf.as_ref().len() {
            return Promise::ok(buf)
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| {
            println!("write transferred this many bytes: {}", n);
            let total_written = n as usize + already_written;
            if n == 0 {
                println!("wrote zero bytes!?");
            }

            SocketStreamInner::write_internal(inner2, buf, total_written)
        });

        result
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use decoders::basics::*;
use decoders::Buffer;
use std::str;

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CiffTag {
  Null         = 0x0000,
  ColorInfo1   = 0x0032,
  MakeModel    = 0x080a,
  ShotInfo     = 0x102a,
  ColorInfo2   = 0x102c,
  WhiteBalance = 0x10a9,
  SensorInfo   = 0x1031,
  ImageInfo    = 0x1810,
  DecoderTable = 0x1835,
  RawData      = 0x2005,
  SubIFD       = 0x300a,
  Exif         = 0x300b,
}
}

fn ct (tag: CiffTag) -> u16 {
  tag as u16
}

#[derive(Debug, Copy, Clone)]
pub struct CiffEntry<'a> {
  pub tag: u16,
  pub typ: u16,
  pub count: usize,
  pub bytesize: usize,
  pub data_offset: usize,
  pub data: &'a [u8],
}

#[derive(Debug, Clone)]
pub struct CiffIFD<'a> {
  entries: HashMap<u16,CiffEntry<'a>>,
  subifds: Vec<CiffIFD<'a>>,
}

pub fn is_ciff(buf: &[u8]) -> bool {
  buf[6..14] == b"HEAPCCDR"[..]
}

impl<'a> CiffIFD<'a> {
  pub fn new_file(buf: &'a Buffer) -> Result<CiffIFD<'a>,String> {
    let data = &buf.buf;
    CiffIFD::new(data, LEu32(data,2) as usize, buf.size, 1)
  }

  pub fn new(buf: &'a[u8], start: usize, end: usize, depth: u32) -> Result<CiffIFD<'a>, String> {
    let mut entries = HashMap::new();
    let mut subifds = Vec::new();

    let valuedata_size = LEu32(buf, end-4) as usize;
    let dircount = LEu16(buf, start+valuedata_size) as usize;

    for i in 0..dircount {
      let entry_offset: usize = start+valuedata_size+2+i*10;
      let e = try!(CiffEntry::new(buf, start, entry_offset));
      if e.typ == 0x2800 || e.typ == 0x3000 { // SubIFDs
        if depth < 10 { // Avoid infinite looping IFDs
          let ifd = CiffIFD::new(buf, e.data_offset, e.data_offset+e.bytesize, depth+1);
          match ifd {
            Ok(val) => {subifds.push(val);},
            Err(_) => {entries.insert(e.tag, e);}, // Ignore unparsable IFDs
          }
        }
      } else {
        entries.insert(e.tag, e);
      }
    }

    Ok(CiffIFD {
      entries: entries,
      subifds: subifds,
    })
  }

  pub fn find_entry(&self, tag: CiffTag) -> Option<&CiffEntry> {
    if self.entries.contains_key(&ct(tag)) {
      self.entries.get(&ct(tag))
    } else {
      for ifd in &self.subifds {
        match ifd.find_entry(tag) {
          Some(x) => return Some(x),
          None => {},
        }
      }
      None
    }
  }
}

impl<'a> CiffEntry<'a> {
  pub fn new(buf: &'a[u8], value_data: usize, offset: usize) -> Result<CiffEntry<'a>, String> {
    let p = LEu16(buf, offset);
    let tag = p & 0x3fff;
    let datalocation = (p & 0xc000) as usize;
    let typ = p & 0x3800;

    let (bytesize, data_offset) = match datalocation {
      // Data is offset in value_data
      0x0000 => (LEu32(buf, offset+2) as usize, LEu32(buf, offset+6) as usize + value_data),
      // Data is stored directly in entry
      0x4000 => (8, offset+2),
      val => return Err(format!("CIFF: Don't know about data location {:x}", val).to_string()),
    };
    let data = &buf[data_offset..data_offset+bytesize];
    let count = bytesize >> CiffEntry::element_shift(typ);

    Ok(CiffEntry {
      tag: tag,
      typ: typ,
      count: count,
      bytesize: bytesize,
      data_offset: data_offset,
      data: data,
    })
  }

  pub fn element_shift(typ: u16) -> usize {
    match typ {
      // Byte and ASCII
      0x0000 | 0x8000                   => 0,
      // Short
      0x1000                            => 1,
      // Long, Mix, Sub1 and Sub2
      0x1800 | 0x2000 | 0x2800 | 0x3000 => 2,
      // Default to 0
      _                                 => 0,
    }
  }

  pub fn get_strings(&self) -> Vec<String> {
    String::from_utf8_lossy(self.data).split_terminator("\0").map(|x| x.to_string()).collect()
  }

  pub fn get_u32(&self, idx: usize) -> u32 {
    match self.typ {
      0x0000 | 0x8000                       => self.data[idx] as u32,
      0x1000                                => LEu16(self.data, idx*2) as u32,
      0x1800 | 0x2000 | 0x2800 | 0x3000     => LEu32(self.data, idx*4),
      _ => panic!(format!("Trying to read typ {} for a u32", self.typ).to_string()),
    }
  }

  pub fn get_usize(&self, idx: usize) -> usize { self.get_u32(idx) as usize }
  pub fn get_f32(&self, idx: usize) -> f32 { self.get_u32(idx) as f32 }
  pub fn get_force_u16(&self, idx: usize) -> u16 { LEu16(self.data, idx*2) }
}
<commit_msg>Remove unneeded include<commit_after>use std::collections::HashMap;
use decoders::basics::*;
use decoders::Buffer;

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CiffTag {
  Null         = 0x0000,
  ColorInfo1   = 0x0032,
  MakeModel    = 0x080a,
  ShotInfo     = 0x102a,
  ColorInfo2   = 0x102c,
  WhiteBalance = 0x10a9,
  SensorInfo   = 0x1031,
  ImageInfo    = 0x1810,
  DecoderTable = 0x1835,
  RawData      = 0x2005,
  SubIFD       = 0x300a,
  Exif         = 0x300b,
}
}

fn ct (tag: CiffTag) -> u16 {
  tag as u16
}

#[derive(Debug, Copy, Clone)]
pub struct CiffEntry<'a> {
  pub tag: u16,
  pub typ: u16,
  pub count: usize,
  pub bytesize: usize,
  pub data_offset: usize,
  pub data: &'a [u8],
}

#[derive(Debug, Clone)]
pub struct CiffIFD<'a> {
  entries: HashMap<u16,CiffEntry<'a>>,
  subifds: Vec<CiffIFD<'a>>,
}

pub fn is_ciff(buf: &[u8]) -> bool {
  buf[6..14] == b"HEAPCCDR"[..]
}

impl<'a> CiffIFD<'a> {
  pub fn new_file(buf: &'a Buffer) -> Result<CiffIFD<'a>,String> {
    let data = &buf.buf;
    CiffIFD::new(data, LEu32(data,2) as usize, buf.size, 1)
  }

  pub fn new(buf: &'a[u8], start: usize, end: usize, depth: u32) -> Result<CiffIFD<'a>, String> {
    let mut entries = HashMap::new();
    let mut subifds = Vec::new();

    let valuedata_size = LEu32(buf, end-4) as usize;
    let dircount = LEu16(buf, start+valuedata_size) as usize;

    for i in 0..dircount {
      let entry_offset: usize = start+valuedata_size+2+i*10;
      let e = try!(CiffEntry::new(buf, start, entry_offset));
      if e.typ == 0x2800 || e.typ == 0x3000 { // SubIFDs
        if depth < 10 { // Avoid infinite looping IFDs
          let ifd = CiffIFD::new(buf, e.data_offset, e.data_offset+e.bytesize, depth+1);
          match ifd {
            Ok(val) => {subifds.push(val);},
            Err(_) => {entries.insert(e.tag, e);}, // Ignore unparsable IFDs
          }
        }
      } else {
        entries.insert(e.tag, e);
      }
    }

    Ok(CiffIFD {
      entries: entries,
      subifds: subifds,
    })
  }

  pub fn find_entry(&self, tag: CiffTag) -> Option<&CiffEntry> {
    if self.entries.contains_key(&ct(tag)) {
      self.entries.get(&ct(tag))
    } else {
      for ifd in &self.subifds {
        match ifd.find_entry(tag) {
          Some(x) => return Some(x),
          None => {},
        }
      }
      None
    }
  }
}

impl<'a> CiffEntry<'a> {
  pub fn new(buf: &'a[u8], value_data: usize, offset: usize) -> Result<CiffEntry<'a>, String> {
    let p = LEu16(buf, offset);
    let tag = p & 0x3fff;
    let datalocation = (p & 0xc000) as usize;
    let typ = p & 0x3800;

    let (bytesize, data_offset) = match datalocation {
      // Data is offset in value_data
      0x0000 => (LEu32(buf, offset+2) as usize, LEu32(buf, offset+6) as usize + value_data),
      // Data is stored directly in entry
      0x4000 => (8, offset+2),
      val => return Err(format!("CIFF: Don't know about data location {:x}", val).to_string()),
    };
    let data = &buf[data_offset..data_offset+bytesize];
    let count = bytesize >> CiffEntry::element_shift(typ);

    Ok(CiffEntry {
      tag: tag,
      typ: typ,
      count: count,
      bytesize: bytesize,
      data_offset: data_offset,
      data: data,
    })
  }

  pub fn element_shift(typ: u16) -> usize {
    match typ {
      // Byte and ASCII
      0x0000 | 0x8000                   => 0,
      // Short
      0x1000                            => 1,
      // Long, Mix, Sub1 and Sub2
      0x1800 | 0x2000 | 0x2800 | 0x3000 => 2,
      // Default to 0
      _                                 => 0,
    }
  }

  pub fn get_strings(&self) -> Vec<String> {
    String::from_utf8_lossy(self.data).split_terminator("\0").map(|x| x.to_string()).collect()
  }

  pub fn get_u32(&self, idx: usize) -> u32 {
    match self.typ {
      0x0000 | 0x8000                       => self.data[idx] as u32,
      0x1000                                => LEu16(self.data, idx*2) as u32,
      0x1800 | 0x2000 | 0x2800 | 0x3000     => LEu32(self.data, idx*4),
      _ => panic!(format!("Trying to read typ {} for a u32", self.typ).to_string()),
    }
  }

  pub fn get_usize(&self, idx: usize) -> usize { self.get_u32(idx) as usize }
  pub fn get_f32(&self, idx: usize) -> f32 { self.get_u32(idx) as f32 }
  pub fn get_force_u16(&self, idx: usize) -> u16 { LEu16(self.data, idx*2) }
}
<|endoftext|>


<commit_before>use rustc::hir::def_id::DefId;
use rustc::traits;
use rustc::ty::layout::Layout;
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, Ty};
use rustc::mir;
use syntax::codemap::Span;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext, monomorphize_field_ty, StackPopCleanup};
use lvalue::{Lvalue, LvalueExtra};
use memory::Pointer;
use value::PrimVal;
use value::Value;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    /// Creates stack frames for all drop impls. See `drop` for the actual content.
    pub fn eval_drop_impls(&mut self, drops: Vec<(DefId, Value, &'tcx Substs<'tcx>)>, span: Span) -> EvalResult<'tcx> {
        // add them to the stack in reverse order, because the impl that needs to run the last
        // is the one that needs to be at the bottom of the stack
        for (drop_def_id, self_arg, substs) in drops.into_iter().rev() {
            let mir = self.load_mir(drop_def_id)?;
            trace!("substs for drop glue: {:?}", substs);
            self.push_stack_frame(
                drop_def_id,
                span,
                mir,
                substs,
                Lvalue::from_ptr(Pointer::zst_ptr()),
                StackPopCleanup::None,
                Vec::new(),
            )?;
            let mut arg_locals = self.frame().mir.args_iter();
            let first = arg_locals.next().expect("drop impl has self arg");
            assert!(arg_locals.next().is_none(), "drop impl should have only one arg");
            let dest = self.eval_lvalue(&mir::Lvalue::Local(first))?;
            let ty = self.frame().mir.local_decls[first].ty;
            self.write_value(self_arg, dest, ty)?;
        }
        Ok(())
    }

    /// push DefIds of drop impls and their argument on the given vector
    pub fn drop(
        &mut self,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx> {
        if !self.type_needs_drop(ty) {
            debug!("no need to drop {:?}", ty);
            return Ok(());
        }
        trace!("-need to drop {:?} at {:?}", ty, lval);

        match ty.sty {
            // special case `Box` to deallocate the inner allocation
            ty::TyAdt(ref def, _) if def.is_box() => {
                let contents_ty = ty.boxed_ty();
                let val = self.read_lvalue(lval);
                // we are going through the read_value path, because that already does all the
                // checks for the trait object types. We'd only be repeating ourselves here.
                let val = self.follow_by_ref_value(val, ty)?;
                trace!("box dealloc on {:?}", val);
                match val {
                    Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
                    Value::ByVal(ptr) => {
                        assert!(self.type_is_sized(contents_ty));
                        let contents_ptr = ptr.to_ptr()?;
                        self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
                    },
                    Value::ByValPair(prim_ptr, extra) => {
                        let ptr = prim_ptr.to_ptr()?;
                        let extra = match self.tcx.struct_tail(contents_ty).sty {
                            ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?),
                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?),
                            _ => bug!("invalid fat pointer type: {}", ty),
                        };
                        self.drop(Lvalue::Ptr { ptr, extra }, contents_ty, drop)?;
                    },
                }
                // We cannot use Box's destructor, because it is a no-op and only exists to reduce
                // the number of hacks required in the compiler around the Box type.
                let box_free_fn = self.tcx.lang_items.box_free_fn().expect("no box_free lang item");
                let substs = self.tcx.intern_substs(&[Kind::from(contents_ty)]);
                // this is somewhat hacky, but hey, there's no representation difference between
                // pointers, `Box`es and references, so
                // #[lang = "box_free"] unsafe fn box_free<T>(ptr: *mut T)
                // is the same as
                // fn drop(&mut self) if Self is Box<T>
                drop.push((box_free_fn, val, substs));
            },

            ty::TyAdt(adt_def, substs) => {
                // FIXME: some structs are represented as ByValPair
                let mut lval = self.force_allocation(lval)?;
                let adt_ptr = match lval {
                    Lvalue::Ptr { ptr, .. } => ptr,
                    _ => bug!("force allocation can only yield Lvalue::Ptr"),
                };

                // run drop impl before the fields' drop impls
                if let Some(drop_def_id) = adt_def.destructor() {
                    let trait_ref = ty::Binder(ty::TraitRef {
                        def_id: self.tcx.lang_items.drop_trait().unwrap(),
                        substs: self.tcx.mk_substs_trait(ty, &[]),
                    });
                    let vtable = match self.fulfill_obligation(trait_ref) {
                        traits::VtableImpl(data) => data,
                        _ => bug!("dtor for {:?} is not an impl???", ty)
                    };
                    drop.push((drop_def_id, Value::ByVal(PrimVal::Ptr(adt_ptr)), vtable.substs));
                }

                let layout = self.type_layout(ty)?;
                let fields = match *layout {
                    Layout::Univariant { .. } => &adt_def.struct_variant().fields,
                    Layout::General { .. } => {
                        let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
                        let ptr = self.force_allocation(lval)?.to_ptr();
                        match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u128_unchecked()) {
                            Some(i) => {
                                lval = Lvalue::Ptr {
                                    ptr,
                                    extra: LvalueExtra::DowncastVariant(i),
                                };
                                &adt_def.variants[i].fields
                            },
                            None => return Err(EvalError::InvalidDiscriminant),
                        }
                    },
                    Layout::StructWrappedNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            &adt_def.variants[discr as usize].fields
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::RawNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            assert_eq!(adt_def.variants[discr as usize].fields.len(), 1);
                            let field_ty = &adt_def.variants[discr as usize].fields[0];
                            let field_ty = monomorphize_field_ty(self.tcx, field_ty, substs);
                            // FIXME: once read_discriminant_value works with lvalue, don't force
                            // alloc in the RawNullablePointer case
                            self.drop(lval, field_ty, drop)?;
                            return Ok(());
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::CEnum { .. } => return Ok(()),
                    _ => bug!("{:?} is not an adt layout", layout),
                };
                let tcx = self.tcx;
                self.drop_fields(
                    fields.iter().map(|field| monomorphize_field_ty(tcx, field, substs)),
                    lval,
                    ty,
                    drop,
                )?;
            },
            ty::TyTuple(fields, _) => self.drop_fields(fields.into_iter().cloned(), lval, ty, drop)?,
            ty::TyDynamic(..) => {
                let (ptr, vtable) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => (ptr, vtable),
                    _ => bug!("expected an lvalue with a vtable"),
                };
                let drop_fn = self.memory.read_ptr(vtable)?;
                // some values don't need to call a drop impl, so the value is null
                if drop_fn != Pointer::from_int(0) {
                    let real_ty = self.memory.get_fn(drop_fn.alloc_id)?.expect_drop_glue_real_ty()?;
                    self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
                } else {
                    // just a sanity check
                    assert_eq!(drop_fn.offset, 0);
                }
            },
            ty::TySlice(elem_ty) => {
                let (ptr, len) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len),
                    _ => bug!("expected an lvalue with a length"),
                };
                let size = self.type_size(elem_ty)?.expect("slice element must be sized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..len {
                    self.drop(Lvalue::from_ptr(ptr.offset(i * size)), elem_ty, drop)?;
                }
            },
            ty::TyArray(elem_ty, len) => {
                let lval = self.force_allocation(lval)?;
                let (ptr, extra) = match lval {
                    Lvalue::Ptr { ptr, extra } => (ptr, extra),
                    _ => bug!("expected an lvalue with optional extra data"),
                };
                let size = self.type_size(elem_ty)?.expect("array element cannot be unsized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..(len as u64) {
                    self.drop(Lvalue::Ptr { ptr: ptr.offset(i * size), extra }, elem_ty, drop)?;
                }
            },
            // FIXME: what about TyClosure and TyAnon?
            // other types do not need to process drop
            _ => {},
        }

        Ok(())
    }

    fn drop_fields<I>(
        &mut self,
        fields: I,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx>
        where I: Iterator<Item=Ty<'tcx>>,
    {
        trace!("drop_fields: {:?} of type {}", lval, ty);
        for (i, field_ty) in fields.enumerate() {
            let field_lval = self.lvalue_field(lval, i, ty, field_ty)?;
            self.drop(field_lval, field_ty, drop)?;
        }
        Ok(())
    }

    fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
        self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
    }
}
<commit_msg>Do drop glue for closures.<commit_after>use rustc::hir::def_id::DefId;
use rustc::traits;
use rustc::ty::layout::Layout;
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, Ty};
use rustc::mir;
use syntax::codemap::Span;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext, monomorphize_field_ty, StackPopCleanup};
use lvalue::{Lvalue, LvalueExtra};
use memory::Pointer;
use value::PrimVal;
use value::Value;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    /// Creates stack frames for all drop impls. See `drop` for the actual content.
    pub fn eval_drop_impls(&mut self, drops: Vec<(DefId, Value, &'tcx Substs<'tcx>)>, span: Span) -> EvalResult<'tcx> {
        // add them to the stack in reverse order, because the impl that needs to run the last
        // is the one that needs to be at the bottom of the stack
        for (drop_def_id, self_arg, substs) in drops.into_iter().rev() {
            let mir = self.load_mir(drop_def_id)?;
            trace!("substs for drop glue: {:?}", substs);
            self.push_stack_frame(
                drop_def_id,
                span,
                mir,
                substs,
                Lvalue::from_ptr(Pointer::zst_ptr()),
                StackPopCleanup::None,
                Vec::new(),
            )?;
            let mut arg_locals = self.frame().mir.args_iter();
            let first = arg_locals.next().expect("drop impl has self arg");
            assert!(arg_locals.next().is_none(), "drop impl should have only one arg");
            let dest = self.eval_lvalue(&mir::Lvalue::Local(first))?;
            let ty = self.frame().mir.local_decls[first].ty;
            self.write_value(self_arg, dest, ty)?;
        }
        Ok(())
    }

    /// push DefIds of drop impls and their argument on the given vector
    pub fn drop(
        &mut self,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx> {
        if !self.type_needs_drop(ty) {
            debug!("no need to drop {:?}", ty);
            return Ok(());
        }
        trace!("need to drop {:?} at {:?}", ty, lval);

        match ty.sty {
            // special case `Box` to deallocate the inner allocation
            ty::TyAdt(ref def, _) if def.is_box() => {
                let contents_ty = ty.boxed_ty();
                let val = self.read_lvalue(lval);
                // we are going through the read_value path, because that already does all the
                // checks for the trait object types. We'd only be repeating ourselves here.
                let val = self.follow_by_ref_value(val, ty)?;
                trace!("box dealloc on {:?}", val);
                match val {
                    Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
                    Value::ByVal(ptr) => {
                        assert!(self.type_is_sized(contents_ty));
                        let contents_ptr = ptr.to_ptr()?;
                        self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
                    },
                    Value::ByValPair(prim_ptr, extra) => {
                        let ptr = prim_ptr.to_ptr()?;
                        let extra = match self.tcx.struct_tail(contents_ty).sty {
                            ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?),
                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?),
                            _ => bug!("invalid fat pointer type: {}", ty),
                        };
                        self.drop(Lvalue::Ptr { ptr, extra }, contents_ty, drop)?;
                    },
                }
                // We cannot use Box's destructor, because it is a no-op and only exists to reduce
                // the number of hacks required in the compiler around the Box type.
                let box_free_fn = self.tcx.lang_items.box_free_fn().expect("no box_free lang item");
                let substs = self.tcx.intern_substs(&[Kind::from(contents_ty)]);
                // this is somewhat hacky, but hey, there's no representation difference between
                // pointers, `Box`es and references, so
                // #[lang = "box_free"] unsafe fn box_free<T>(ptr: *mut T)
                // is the same as
                // fn drop(&mut self) if Self is Box<T>
                drop.push((box_free_fn, val, substs));
            }

            ty::TyAdt(adt_def, substs) => {
                // FIXME: some structs are represented as ByValPair
                let mut lval = self.force_allocation(lval)?;
                let adt_ptr = match lval {
                    Lvalue::Ptr { ptr, .. } => ptr,
                    _ => bug!("force allocation can only yield Lvalue::Ptr"),
                };

                // run drop impl before the fields' drop impls
                if let Some(drop_def_id) = adt_def.destructor() {
                    let trait_ref = ty::Binder(ty::TraitRef {
                        def_id: self.tcx.lang_items.drop_trait().unwrap(),
                        substs: self.tcx.mk_substs_trait(ty, &[]),
                    });
                    let vtable = match self.fulfill_obligation(trait_ref) {
                        traits::VtableImpl(data) => data,
                        _ => bug!("dtor for {:?} is not an impl???", ty)
                    };
                    drop.push((drop_def_id, Value::ByVal(PrimVal::Ptr(adt_ptr)), vtable.substs));
                }

                let layout = self.type_layout(ty)?;
                let fields = match *layout {
                    Layout::Univariant { .. } => &adt_def.struct_variant().fields,
                    Layout::General { .. } => {
                        let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
                        let ptr = self.force_allocation(lval)?.to_ptr();
                        match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u128_unchecked()) {
                            Some(i) => {
                                lval = Lvalue::Ptr {
                                    ptr,
                                    extra: LvalueExtra::DowncastVariant(i),
                                };
                                &adt_def.variants[i].fields
                            },
                            None => return Err(EvalError::InvalidDiscriminant),
                        }
                    },
                    Layout::StructWrappedNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            &adt_def.variants[discr as usize].fields
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::RawNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            assert_eq!(adt_def.variants[discr as usize].fields.len(), 1);
                            let field_ty = &adt_def.variants[discr as usize].fields[0];
                            let field_ty = monomorphize_field_ty(self.tcx, field_ty, substs);
                            // FIXME: once read_discriminant_value works with lvalue, don't force
                            // alloc in the RawNullablePointer case
                            self.drop(lval, field_ty, drop)?;
                            return Ok(());
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::CEnum { .. } => return Ok(()),
                    _ => bug!("{:?} is not an adt layout", layout),
                };
                let tcx = self.tcx;
                self.drop_fields(
                    fields.iter().map(|field| monomorphize_field_ty(tcx, field, substs)),
                    lval,
                    ty,
                    drop,
                )?;
            }

            ty::TyTuple(fields, _) =>
                self.drop_fields(fields.into_iter().cloned(), lval, ty, drop)?,

            ty::TyDynamic(..) => {
                let (ptr, vtable) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => (ptr, vtable),
                    _ => bug!("expected an lvalue with a vtable"),
                };
                let drop_fn = self.memory.read_ptr(vtable)?;
                // some values don't need to call a drop impl, so the value is null
                if drop_fn != Pointer::from_int(0) {
                    let real_ty = self.memory.get_fn(drop_fn.alloc_id)?.expect_drop_glue_real_ty()?;
                    self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
                } else {
                    // just a sanity check
                    assert_eq!(drop_fn.offset, 0);
                }
            }

            ty::TySlice(elem_ty) => {
                let (ptr, len) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len),
                    _ => bug!("expected an lvalue with a length"),
                };
                let size = self.type_size(elem_ty)?.expect("slice element must be sized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..len {
                    self.drop(Lvalue::from_ptr(ptr.offset(i * size)), elem_ty, drop)?;
                }
            }

            ty::TyArray(elem_ty, len) => {
                let lval = self.force_allocation(lval)?;
                let (ptr, extra) = match lval {
                    Lvalue::Ptr { ptr, extra } => (ptr, extra),
                    _ => bug!("expected an lvalue with optional extra data"),
                };
                let size = self.type_size(elem_ty)?.expect("array element cannot be unsized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..(len as u64) {
                    self.drop(Lvalue::Ptr { ptr: ptr.offset(i * size), extra }, elem_ty, drop)?;
                }
            }

            ty::TyClosure(def_id, substs) => {
                let fields = substs.upvar_tys(def_id, self.tcx);
                self.drop_fields(fields, lval, ty, drop)?;
            }

            _ => bug!(),
        }

        Ok(())
    }

    fn drop_fields<I>(
        &mut self,
        fields: I,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx>
        where I: Iterator<Item=Ty<'tcx>>,
    {
        trace!("drop_fields: {:?} of type {}", lval, ty);
        for (i, field_ty) in fields.enumerate() {
            let field_lval = self.lvalue_field(lval, i, ty, field_ty)?;
            self.drop(field_lval, field_ty, drop)?;
        }
        Ok(())
    }

    fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
        self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     int,                    // Program counter (index within ante.code)
    line:   int,                    // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
    buffer: Vec<char>               // Buffer to collect UTF-8 character bytes.
}

impl Ante {
    fn new() -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        Ante {
            pc:     0,
            line:   0,
            code:   vec![],
            vars:   vars,
            labels: HashMap::new(),
            buffer: vec![]
        }
    }

    fn run(&mut self, filename: &str) {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);
        self.parse(program.as_slice())
    }

    // Turn source file into array of cards.
    fn parse(&mut self, program: &str) {
        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new().run("hello.ante".as_slice());
}
<commit_msg>Parse cards<commit_after>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     int,                    // Program counter (index within ante.code)
    line:   int,                    // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
    buffer: Vec<char>               // Buffer to collect UTF-8 character bytes.
}

impl Ante {
    fn new() -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        Ante {
            pc:     0,
            line:   0,
            code:   vec![],
            vars:   vars,
            labels: HashMap::new(),
            buffer: vec![]
        }
    }

    fn run(&mut self, filename: &str) {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);
        self.parse(program.as_slice())
    }

    // Turn source file into array of cards.
    fn parse(&mut self, program: &str) {
        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            self.code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                self.code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, self.code.len()) {
            println!("{:2}) code: /{}:{}/", i, self.code[i].rank, self.code[i].suit);
        }

    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new().run("factorial.ante".as_slice());
}
<|endoftext|>


<commit_before>
<commit_msg>bin expr test<commit_after>use crate::grammar::parsers::testing::test_should_succeed;
use crate::grammar::ast::BinaryExpression;

fn test_binary_expr_simple() {
    test_should_succeed(
        BinaryExpression::parse,
        "2 + 2",
        "",
        |expr| {
            if let
        }
    )
}<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd and Justin Ingram jci5kb
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::os::getcwd;
use extra::getopts;
use std::run::Process;
use std::run::ProcessOutput;
use std::run::ProcessOptions;
use std::option::{Option, None, Some};
use std::io::buffered::BufferedWriter;
use std::io::File;
use std::comm::Chan;

struct Shell {
    cmd_prompt: ~str,
    hist: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {

        Shell {
            cmd_prompt: prompt_str.to_owned(),
            hist: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.hist.push(line);
            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                "history" =>{ self.history(); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            //Let's process the argv

            let endopt = argv.pop_opt();
            let end = match endopt {
		Some(stringy) => { stringy }
		None => { ~"" }
            };

            if end.eq(&~"&") {
		// println("Start in a new process" + end);
		self.run_cmd(program, argv, true);
            } else {
		//println("No new process");
		if !end.eq(&~"") {
		    argv.push(end.to_owned());
		}
		self.run_cmd(program, argv, false);
            }
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		run::process_status(program, argv);
	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }
    /*
    fn makefunky(&mut self, program: &str, argv: &[~str]) -> (proc(&str, &[~str])) {
	proc(program: &str, argv: &[~str]) {

	    // whichprocop.dir = self.cwdopt.as_ref();

	    let mut whichproc = Process::new(program, argv, whichprocop);
	    let mut process = whichproc.unwrap();

	    let mut procout = process.finish_with_output();
	    println(std::str::from_utf8(procout.output));
	}
    }
    */

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);

            //println!("You want to change cwd to {:s}", pstring);

            let npath = Path::new(pstring);

            let mut cpath = getcwd();
            cpath.push(npath);

            if cpath.exists() {
		let mut cpathforopt = cpath.clone();
		std::os::change_dir(&cpath);
		// self.cwd = cpath;
            } else {
		println("Path does not exist!");
            }

        }

        let x = getcwd();

        match x.as_str() {
	    Some(path_str) => {println!("{:s}", path_str); }
	    None	=> {println("Path not representable as string!"); }
        }
    }

    fn history(&mut self) {
	let mut n :int = 1;
	for stringy in self.hist.iter() {
	    let x = stringy.clone();
	    print(n.to_str() + ~"\t" + x);
	    n += 1;
	}
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>syntax changes<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd and Justin Ingram jci5kb
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::os::getcwd;
use extra::getopts;
use std::run::Process;
use std::run::ProcessOutput;
use std::run::ProcessOptions;
use std::option::{Option, None, Some};
use std::io::buffered::BufferedWriter;
use std::io::File;
use std::comm::Chan;

struct Shell {
    cmd_prompt: ~str,
    hist: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {

        Shell {
            cmd_prompt: prompt_str.to_owned(),
            hist: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.hist.push(line);
            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                "history" =>{ self.history(); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            //Let's process the argv

            let endopt = argv.pop_opt();
            let end = match endopt {
		Some(stringy) => { stringy }
		None => { ~"" }
            };

            if end.eq(&~"&") {
		// println("Start in a new process" + end);
		self.run_cmd(program, argv, true);
            } else {
		//println("No new process");
		if !end.eq(&~"") {
		    argv.push(end.to_owned());
		}
		self.run_cmd(program, argv, false);
            }
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		run::process_status(program, argv);
	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }
    /*
    fn makefunky(&mut self, program: &str, argv: &[~str]) -> (proc(&str, &[~str])) {
	proc(program: &str, argv: &[~str]) {

	    // whichprocop.dir = self.cwdopt.as_ref();

	    let mut whichproc = Process::new(program, argv, whichprocop);
	    let mut process = whichproc.unwrap();

	    let mut procout = process.finish_with_output();
	    println(std::str::from_utf8(procout.output));
	}
    }
    */

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);

            //println!("You want to change cwd to {:s}", pstring);

            let npath = Path::new(pstring);

            let mut cpath = getcwd();
            cpath.push(npath);

            if cpath.exists() {
		let mut cpathforopt = cpath.clone();
		std::os::change_dir(&cpath);
		// self.cwd = cpath;
            } else {
		println("Path does not exist!");
            }

        }

        let x = getcwd();

        match x.as_str() {
	    Some(path_str) => {println!("{:s}", path_str); }
	    None	=> {println("Path not representable as string!"); }
        }
    }

    fn history(&mut self) {
	let mut n :int = 1;
	for stringy in self.hist.iter() {
	    let x = stringy.clone();
	    print("[" + n.to_str() + "]" + ~"\t" + x);
	    n += 1;
	}
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>//! Extended attribute support for Darwin and Linux systems.
extern crate libc;

use std::io;
use std::path::Path;
use std::ffi::CString;

pub const ENABLED: bool = cfg!(feature="git") && cfg!(any(target_os="macos", target_os="linux"));

pub trait FileAttributes {
    fn attributes(&self) -> io::Result<Vec<Attribute>>;
    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>>;
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::Yes), &self)
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::No), &self)
    }
}

#[cfg(not(any(target_os = "macos", target_os = "linux")))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }
}

/// Attributes which can be passed to `Attribute::list_with_flags`
#[cfg(any(target_os = "macos", target_os = "linux"))]
#[derive(Copy, Clone)]
pub enum FollowSymlinks {
    Yes,
    No
}

/// Extended attribute
#[derive(Debug, Clone)]
pub struct Attribute {
    pub name: String,
    pub size: usize,
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn list_attrs(lister: lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> {
    let c_path = match path.to_str().and_then(|s| { CString::new(s).ok() }) {
        Some(cstring) => cstring,
        None => return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")),
    };

    let mut names = Vec::new();
    let bufsize = lister.listxattr_first(&c_path);

    if bufsize < 0 {
        return Err(io::Error::last_os_error());
    }
    else if bufsize > 0 {
        let mut buf = vec![0u8; bufsize as usize];
        let err = lister.listxattr_second(&c_path, &mut buf, bufsize);

        if err < 0 {
            return Err(io::Error::last_os_error());
        }

        if err > 0 {
            // End indicies of the attribute names
            // the buffer contains 0-terminates c-strings
            let idx = buf.iter().enumerate().filter_map(|(i, v)|
                if *v == 0 { Some(i) } else { None }
            );
            let mut start = 0;

            for end in idx {
                let c_end = end + 1; // end of the c-string (including 0)
                let size = lister.getxattr(&c_path, &buf[start..c_end]);

                if size > 0 {
                    names.push(Attribute {
                        name: lister.translate_attribute_name(&buf[start..end]),
                        size: size as usize
                    });
                }

                start = c_end;
            }

        }

    }
    Ok(names)
}

#[cfg(target_os = "macos")]
mod lister {
    use std::ffi::CString;
    use libc::{c_int, size_t, ssize_t, c_char, c_void, uint32_t};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, namebuf: *mut c_char,
            size: size_t, options: c_int
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t, position: uint32_t,
            options: c_int
        ) -> ssize_t;
    }

    pub struct Lister {
        c_flags: c_int,
    }

    impl Lister {
        pub fn new(do_follow: FollowSymlinks) -> Lister {
            let c_flags: c_int = match do_follow {
                FollowSymlinks::Yes => 0x0001,
                FollowSymlinks::No  => 0x0000,
            };

            Lister { c_flags: c_flags }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            use std::str::from_utf8_unchecked;

            unsafe {
                from_utf8_unchecked(input).into()
            }
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            unsafe {
                listxattr(c_path.as_ptr(), ptr::null_mut(), 0, self.c_flags)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            unsafe {
                listxattr(
                    c_path.as_ptr(),
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t, self.c_flags
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            unsafe {
                getxattr(
                    c_path.as_ptr(),
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0, 0, self.c_flags
                )
            }
        }
    }
}

#[cfg(target_os = "linux")]
mod lister {
    use std::ffi::CString;
    use libc::{size_t, ssize_t, c_char, c_void};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn llistxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;

        fn lgetxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;
    }

    pub struct Lister {
        follow_symlinks: FollowSymlinks,
    }

    impl Lister {
        pub fn new(follow_symlinks: FollowSymlinks) -> Lister {
            Lister { follow_symlinks: follow_symlinks }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            String::from_utf8_lossy(input).into_owned()
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(c_path.as_ptr(), ptr::null_mut(), 0)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(
                    c_path.as_ptr(),
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            let getxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => getxattr,
                FollowSymlinks::No  => lgetxattr,
            };

            unsafe {
                getxattr(
                    c_path.as_ptr(),
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0
                )
            }
        }
    }
}
<commit_msg>Update xattr.rs<commit_after>//! Extended attribute support for Darwin and Linux systems.
extern crate libc;

use std::io;
use std::path::Path;
use std::ffi::CString;

pub const ENABLED: bool = cfg!(feature="git") && cfg!(any(target_os="macos", target_os="linux"));

pub trait FileAttributes {
    fn attributes(&self) -> io::Result<Vec<Attribute>>;
    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>>;
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::Yes), &self)
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        list_attrs(lister::Lister::new(FollowSymlinks::No), &self)
    }
}

#[cfg(not(any(target_os = "macos", target_os = "linux")))]
impl FileAttributes for Path {
    fn attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }

    fn symlink_attributes(&self) -> io::Result<Vec<Attribute>> {
        Ok(vec![])
    }
}

/// Attributes which can be passed to `Attribute::list_with_flags`
#[cfg(any(target_os = "macos", target_os = "linux"))]
#[derive(Copy, Clone)]
pub enum FollowSymlinks {
    Yes,
    No
}

/// Extended attribute
#[derive(Debug, Clone)]
pub struct Attribute {
    pub name: String,
    pub size: usize,
}

#[cfg(any(target_os = "macos", target_os = "linux"))]
pub fn list_attrs(lister: lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> {
    let c_path = match path.to_str().and_then(|s| { CString::new(s).ok() }) {
        Some(cstring) => cstring,
        None => return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")),
    };

    let mut names = Vec::new();
    let bufsize = lister.listxattr_first(&c_path);

    if bufsize < 0 {
        return Err(io::Error::last_os_error());
    }
    else if bufsize > 0 {
        let mut buf = vec![0u8; bufsize as usize];
        let err = lister.listxattr_second(&c_path, &mut buf, bufsize);

        if err < 0 {
            return Err(io::Error::last_os_error());
        }

        if err > 0 {
            // End indicies of the attribute names
            // the buffer contains 0-terminates c-strings
            let idx = buf.iter().enumerate().filter_map(|(i, v)|
                if *v == 0 { Some(i) } else { None }
            );
            let mut start = 0;

            for end in idx {
                let c_end = end + 1; // end of the c-string (including 0)
                let size = lister.getxattr(&c_path, &buf[start..c_end]);

                if size > 0 {
                    names.push(Attribute {
                        name: lister.translate_attribute_name(&buf[start..end]),
                        size: size as usize
                    });
                }

                start = c_end;
            }

        }

    }
    Ok(names)
}

#[cfg(target_os = "macos")]
mod lister {
    use std::ffi::CString;
    use libc::{c_int, size_t, ssize_t, c_char, c_void, uint32_t};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, namebuf: *mut c_char,
            size: size_t, options: c_int
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t, position: uint32_t,
            options: c_int
        ) -> ssize_t;
    }

    pub struct Lister {
        c_flags: c_int,
    }

    impl Lister {
        pub fn new(do_follow: FollowSymlinks) -> Lister {
            let c_flags: c_int = match do_follow {
                FollowSymlinks::Yes => 0x0001,
                FollowSymlinks::No  => 0x0000,
            };

            Lister { c_flags: c_flags }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            use std::str::from_utf8_unchecked;

            unsafe {
                from_utf8_unchecked(input).into()
            }
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            unsafe {
                listxattr(c_path.as_ptr(), ptr::null_mut(), 0, self.c_flags)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            unsafe {
                listxattr(
                    c_path.as_ptr(),
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t, self.c_flags
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            unsafe {
                getxattr(
                    c_path.as_ptr(),
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0, 0, self.c_flags
                )
            }
        }
    }
}

#[cfg(target_os = "linux")]
mod lister {
    use std::ffi::CString;
    use libc::{size_t, ssize_t, c_char, c_void};
    use super::FollowSymlinks;
    use std::ptr;

    extern "C" {
        fn listxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn llistxattr(
            path: *const c_char, list: *mut c_char, size: size_t
        ) -> ssize_t;

        fn getxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;

        fn lgetxattr(
            path: *const c_char, name: *const c_char,
            value: *mut c_void, size: size_t
        ) -> ssize_t;
    }

    pub struct Lister {
        follow_symlinks: FollowSymlinks,
    }

    impl Lister {
        pub fn new(follow_symlinks: FollowSymlinks) -> Lister {
            Lister { follow_symlinks: follow_symlinks }
        }

        pub fn translate_attribute_name(&self, input: &[u8]) -> String {
            String::from_utf8_lossy(input).into_owned()
        }

        pub fn listxattr_first(&self, c_path: &CString) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(c_path.as_ptr() as *const _, ptr::null_mut(), 0)
            }
        }

        pub fn listxattr_second(&self, c_path: &CString, buf: &mut Vec<u8>, bufsize: ssize_t) -> ssize_t {
            let listxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => listxattr,
                FollowSymlinks::No  => llistxattr,
            };

            unsafe {
                listxattr(
                    c_path.as_ptr() as *const _,
                    buf.as_mut_ptr() as *mut c_char,
                    bufsize as size_t
                )
            }
        }

        pub fn getxattr(&self, c_path: &CString, buf: &[u8]) -> ssize_t {
            let getxattr = match self.follow_symlinks {
                FollowSymlinks::Yes => getxattr,
                FollowSymlinks::No  => lgetxattr,
            };

            unsafe {
                getxattr(
                    c_path.as_ptr() as *const _,
                    buf.as_ptr() as *const c_char,
                    ptr::null_mut(), 0
                )
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Allow single quotes in identifiers<commit_after><|endoftext|>