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

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Tag {
  ImageWidth     = 0x0100,
  ImageLength    = 0x0101,
  BitsPerSample  = 0x0102,
  Compression    = 0x0103,
  Make           = 0x010F,
  Model          = 0x0110,
  StripOffsets   = 0x0111,
  StripByteCounts= 0x0117,
  SubIFDs        = 0x014A,
  SonyCurve      = 0x7010,
  SonyOffset     = 0x7200,
  SonyLength     = 0x7201,
  SonyKey        = 0x7221,
  SonyGRBG       = 0x7303,
  SonyRGGB       = 0x7313,
  ExifIFDPointer = 0x8769,
  DNGPrivateArea = 0xC634,
}
}
                          // 0-1-2-3-4-5-6-7-8-9-10-11-12-13
const DATASHIFTS: [u8;14] = [0,0,0,1,2,3,0,0,1,2, 3, 2, 3, 2];

fn t (tag: Tag) -> u16 {
  tag as u16
}

#[derive(Debug, Copy, Clone)]
pub struct TiffEntry<'a> {
  tag: u16,
  typ: u16,
  count: u32,
  data: &'a [u8],
  endian: Endian,
}

#[derive(Debug, Clone)]
pub struct TiffIFD<'a> {
  entries: HashMap<u16,TiffEntry<'a>>,
  subifds: Vec<TiffIFD<'a>>,
  nextifd: usize,
  endian: Endian,
}

impl<'a> TiffIFD<'a> {
  pub fn new_root(buf: &'a[u8], offset: usize, depth: u32, e: Endian) -> TiffIFD<'a> {
    let mut subifds = Vec::new();
    let mut nextifd = e.ru32(buf, offset) as usize;

    for _ in 0..100 { // Never read more than 100 IFDs
      let ifd = TiffIFD::new(buf, nextifd, 0, depth, e).unwrap();
      nextifd = ifd.nextifd;
      subifds.push(ifd);
      if nextifd == 0 {
        break
      }
    }

    TiffIFD {
      entries: HashMap::new(),
      subifds: subifds,
      nextifd: 0,
      endian: e,
    }
  }

  pub fn new(buf: &'a[u8], offset: usize, base_offset: usize, depth: u32, e: Endian) -> Result<TiffIFD<'a>, String> {
    let mut entries = HashMap::new();
    let mut subifds = Vec::new();

    let num = e.ru16(buf, offset); // Directory entries in this IFD
    if num > 4000 {
      return Err("too many entries in IFD".to_string())
    }
    for i in 0..num {
      let entry_offset: usize = offset + 2 + (i as usize)*12;
      if Tag::from_u16(e.ru16(buf, entry_offset)).is_none() {
        // Skip entries we don't know about to speedup decoding
        continue;
      }
      let entry = TiffEntry::new(buf, entry_offset, base_offset, e);

      if entry.tag == t(Tag::SubIFDs) || entry.tag == t(Tag::ExifIFDPointer) {
        if depth < 10 { // Avoid infinite looping IFDs
          for i in 0..entry.count {
            let ifd = TiffIFD::new(buf, entry.get_u32(i as usize) as usize, base_offset, depth+1, e);
            match ifd {
              Ok(val) => {subifds.push(val);},
              Err(_) => {entries.insert(entry.tag, entry);}, // Ignore unparsable IFDs
            }
          }
        }
      } else {
        entries.insert(entry.tag, entry);
      }
    }

    Ok(TiffIFD {
      entries: entries,
      subifds: subifds,
      nextifd: e.ru32(buf, offset + (2+num*12) as usize) as usize,
      endian: e,
    })
  }

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

  pub fn find_ifds_with_tag(&self, tag: Tag) -> Vec<&TiffIFD> {
    let mut ifds = Vec::new();
    for ifd in &self.subifds {
      if ifd.entries.contains_key(&t(tag)) {
        ifds.push(ifd);
      }
      ifds.extend(ifd.find_ifds_with_tag(tag));
    }
    ifds
  }
}

impl<'a> TiffEntry<'a> {
  pub fn new(buf: &'a[u8], offset: usize, base_offset: usize, e: Endian) -> TiffEntry<'a> {
    let tag = e.ru16(buf, offset);
    let mut typ = e.ru16(buf, offset+2);
    let count = e.ru32(buf, offset+4);

    // If we don't know the type assume byte data
    if typ == 0 || typ > 13 {
      typ = 1;
    }

    let bytesize: usize = (count as usize) << DATASHIFTS[typ as usize];
    let doffset: usize = if bytesize <= 4 {
      (offset + 8)
    } else {
      (e.ru32(buf, offset+8) as usize) - base_offset
    };

    TiffEntry {
      tag: tag,
      typ: typ,
      count: count,
      data: &buf[doffset .. doffset+bytesize],
      endian: e,
    }
  }

  pub fn get_u32(&self, idx: usize) -> u32 {
    self.endian.ru32(self.data, idx*4)
  }

  pub fn get_u16(&self, idx: usize) -> u16 {
    self.endian.ru16(self.data, idx*2)
  }

  pub fn get_str(&self) -> &str {
    match str::from_utf8(&self.data[0..self.data.len()-1]) {
      Result::Ok(val) => val.trim(),
      Result::Err(err) => panic!(err),
    }
  }
}
<commit_msg>TIFF: truncate strings on \0<commit_after>use std::collections::HashMap;
use decoders::basics::*;
use std::str;
use num::FromPrimitive;

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Tag {
  ImageWidth     = 0x0100,
  ImageLength    = 0x0101,
  BitsPerSample  = 0x0102,
  Compression    = 0x0103,
  Make           = 0x010F,
  Model          = 0x0110,
  StripOffsets   = 0x0111,
  StripByteCounts= 0x0117,
  SubIFDs        = 0x014A,
  SonyCurve      = 0x7010,
  SonyOffset     = 0x7200,
  SonyLength     = 0x7201,
  SonyKey        = 0x7221,
  SonyGRBG       = 0x7303,
  SonyRGGB       = 0x7313,
  ExifIFDPointer = 0x8769,
  DNGPrivateArea = 0xC634,
}
}
                          // 0-1-2-3-4-5-6-7-8-9-10-11-12-13
const DATASHIFTS: [u8;14] = [0,0,0,1,2,3,0,0,1,2, 3, 2, 3, 2];

fn t (tag: Tag) -> u16 {
  tag as u16
}

#[derive(Debug, Copy, Clone)]
pub struct TiffEntry<'a> {
  tag: u16,
  typ: u16,
  count: u32,
  data: &'a [u8],
  endian: Endian,
}

#[derive(Debug, Clone)]
pub struct TiffIFD<'a> {
  entries: HashMap<u16,TiffEntry<'a>>,
  subifds: Vec<TiffIFD<'a>>,
  nextifd: usize,
  endian: Endian,
}

impl<'a> TiffIFD<'a> {
  pub fn new_root(buf: &'a[u8], offset: usize, depth: u32, e: Endian) -> TiffIFD<'a> {
    let mut subifds = Vec::new();
    let mut nextifd = e.ru32(buf, offset) as usize;

    for _ in 0..100 { // Never read more than 100 IFDs
      let ifd = TiffIFD::new(buf, nextifd, 0, depth, e).unwrap();
      nextifd = ifd.nextifd;
      subifds.push(ifd);
      if nextifd == 0 {
        break
      }
    }

    TiffIFD {
      entries: HashMap::new(),
      subifds: subifds,
      nextifd: 0,
      endian: e,
    }
  }

  pub fn new(buf: &'a[u8], offset: usize, base_offset: usize, depth: u32, e: Endian) -> Result<TiffIFD<'a>, String> {
    let mut entries = HashMap::new();
    let mut subifds = Vec::new();

    let num = e.ru16(buf, offset); // Directory entries in this IFD
    if num > 4000 {
      return Err("too many entries in IFD".to_string())
    }
    for i in 0..num {
      let entry_offset: usize = offset + 2 + (i as usize)*12;
      if Tag::from_u16(e.ru16(buf, entry_offset)).is_none() {
        // Skip entries we don't know about to speedup decoding
        continue;
      }
      let entry = TiffEntry::new(buf, entry_offset, base_offset, e);

      if entry.tag == t(Tag::SubIFDs) || entry.tag == t(Tag::ExifIFDPointer) {
        if depth < 10 { // Avoid infinite looping IFDs
          for i in 0..entry.count {
            let ifd = TiffIFD::new(buf, entry.get_u32(i as usize) as usize, base_offset, depth+1, e);
            match ifd {
              Ok(val) => {subifds.push(val);},
              Err(_) => {entries.insert(entry.tag, entry);}, // Ignore unparsable IFDs
            }
          }
        }
      } else {
        entries.insert(entry.tag, entry);
      }
    }

    Ok(TiffIFD {
      entries: entries,
      subifds: subifds,
      nextifd: e.ru32(buf, offset + (2+num*12) as usize) as usize,
      endian: e,
    })
  }

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

  pub fn find_ifds_with_tag(&self, tag: Tag) -> Vec<&TiffIFD> {
    let mut ifds = Vec::new();
    for ifd in &self.subifds {
      if ifd.entries.contains_key(&t(tag)) {
        ifds.push(ifd);
      }
      ifds.extend(ifd.find_ifds_with_tag(tag));
    }
    ifds
  }
}

impl<'a> TiffEntry<'a> {
  pub fn new(buf: &'a[u8], offset: usize, base_offset: usize, e: Endian) -> TiffEntry<'a> {
    let tag = e.ru16(buf, offset);
    let mut typ = e.ru16(buf, offset+2);
    let count = e.ru32(buf, offset+4);

    // If we don't know the type assume byte data
    if typ == 0 || typ > 13 {
      typ = 1;
    }

    let bytesize: usize = (count as usize) << DATASHIFTS[typ as usize];
    let doffset: usize = if bytesize <= 4 {
      (offset + 8)
    } else {
      (e.ru32(buf, offset+8) as usize) - base_offset
    };

    TiffEntry {
      tag: tag,
      typ: typ,
      count: count,
      data: &buf[doffset .. doffset+bytesize],
      endian: e,
    }
  }

  pub fn get_u32(&self, idx: usize) -> u32 {
    self.endian.ru32(self.data, idx*4)
  }

  pub fn get_u16(&self, idx: usize) -> u16 {
    self.endian.ru16(self.data, idx*2)
  }

  pub fn get_str(&self) -> &str {
    // Truncate the string when there are \0 bytes
    let len = match self.data.iter().position(|&x| x == 0) {
      Some(p) => p,
      None => self.data.len(),
    };
    match str::from_utf8(&self.data[0..len]) {
      Result::Ok(val) => val.trim(),
      Result::Err(err) => panic!(err),
    }
  }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::cmp::{max, min};
use std::mem;

use rustbox::keyboard::Key;
use rustbox::{RustBox};

use tui::style;
use tui::termbox;
use tui::widget::{WidgetRet};

// TODO: Make these settings
const SCROLLOFF : i32 = 5;
const HIST_SIZE : usize = 30;

pub struct TextField {
    /// The message that's currently being edited (not yet sent)
    buffer : Vec<char>,

    /// Cursor in currently shown line
    cursor : i32,

    /// Horizontal scroll
    scroll : i32,

    /// Width of the widget
    width : i32,

    /// A history of sent messages/commands. Once added messages are never
    /// modified. A modification attempt should result in a new buffer with a
    /// copy of the vector in history. (old contents of the buffer will be lost)
    history : Vec<Vec<char>>,

    /// Only available when moving in `history` vector.
    /// INVARIANT: When available, it's a valid index in history.
    hist_curs : Option<i32>,
}

impl TextField {
    pub fn new(width : i32) -> TextField {
        TextField {
            buffer: Vec::with_capacity(512),
            cursor: 0,
            scroll: 0,
            width: width,
            history: Vec::with_capacity(HIST_SIZE),
            hist_curs: None,
        }
    }

    pub fn resize(&mut self, width : i32, _ : i32) {
        self.width = width;
        let cursor = self.cursor;
        self.move_cursor(cursor);
    }

    pub fn draw(&self, _ : &RustBox, pos_x : i32, pos_y : i32) {
        // draw text
        let line_borrow : &[char] = {
            if let Some(hist_curs) = self.hist_curs {
                self.history[hist_curs as usize].borrow()
            } else {
                self.buffer.borrow()
            }
        };

        let slice : &[char] =
            &line_borrow[ self.scroll as usize ..
                          min(line_borrow.len(), (self.scroll + self.width) as usize) ];

        termbox::print_chars(pos_x, pos_y, style::USER_MSG.fg, style::USER_MSG.bg, slice);

        // draw cursor
        termbox::print_char(pos_x + self.cursor - self.scroll, pos_y,
                            style::CURSOR.fg, style::CURSOR.bg,
                            *line_borrow.get(self.cursor as usize).unwrap_or(&' '));
    }

    pub fn keypressed(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Char(ch) => {
                self.modify();
                self.buffer.insert(self.cursor as usize, ch);
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Backspace => {
                if self.cursor > 0 {
                    self.modify();
                    self.buffer.remove(self.cursor as usize - 1);
                    self.dec_cursor();
                }
                WidgetRet::KeyHandled
            },

            Key::Ctrl(ch) => {
                if ch == 'a' {
                    self.move_cursor(0);
                    WidgetRet::KeyHandled
                } else if ch == 'e' {
                    let cur = self.line_len();
                    self.move_cursor(cur);
                    WidgetRet::KeyHandled
                } else if ch == 'k' {
                    self.modify();
                    self.buffer.drain(self.cursor as usize ..);
                    WidgetRet::KeyHandled
                } else if ch == 'w' {
                    self.modify();
                    // TODO: First consume whitespace under the cursor
                    let end_range = self.cursor as usize;
                    let mut begin_range = max(0, self.cursor - 1) as usize;
                    while begin_range > 0
                            && !self.buffer[begin_range].is_whitespace() {
                        begin_range -= 1;
                    }
                    self.buffer.drain(begin_range .. end_range);
                    self.move_cursor(begin_range as i32);
                    WidgetRet::KeyHandled
                } else {
                    WidgetRet::KeyIgnored
                }
            },

            Key::Left => {
                self.dec_cursor();
                WidgetRet::KeyHandled
            },

            Key::Right => {
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Enter => {
                let ret = mem::replace(&mut self.buffer, Vec::new());
                if self.history.len() == HIST_SIZE {
                    let mut reuse = self.history.remove(0);
                    reuse.clear();
                    reuse.extend_from_slice(&ret);
                    self.history.push(reuse);
                } else {
                    self.history.push(ret.clone());
                }
                self.move_cursor(0);
                if ret.len() == 0 {
                    WidgetRet::KeyHandled
                } else {
                    WidgetRet::Input(ret)
                }
            },

            ////////////////////////////////////////////////////////////////////
            // Scrolling in history

            Key::Up => {
                match self.hist_curs {
                    Some(hist_curs) if hist_curs > 0 => {
                        self.hist_curs = Some(hist_curs - 1);
                        let cur = self.line_len();
                        self.move_cursor(cur);
                    },
                    Some(_) => {},
                    None => {
                        if !self.history.is_empty() {
                            self.hist_curs = Some((self.history.len() as i32) - 1);
                            let cur = self.line_len();
                            self.move_cursor(cur);
                        }
                    }
                }
                WidgetRet::KeyHandled
            },

            Key::Down => {
                match self.hist_curs {
                    Some(hist_curs) => {
                        if (hist_curs as usize) < self.history.len() - 1 {
                            self.hist_curs = Some(hist_curs + 1);
                            let cur = self.line_len();
                            self.move_cursor(cur);
                        } else {
                            self.hist_curs = None;
                            let cur = self.line_len();
                            self.move_cursor(cur);
                        }
                    },
                    None => {}
                }
                WidgetRet::KeyHandled
            },

            ////////////////////////////////////////////////////////////////////

            _ => WidgetRet::KeyIgnored,
        }
    }

    #[inline]
    fn line_len(&self) -> i32 {
        if let Some(hist_curs) = self.hist_curs {
            self.history[hist_curs as usize].len() as i32
        } else {
            self.buffer.len() as i32
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // We never modify history, so if the user attempts at a modification, we
    // just make the history entry current message by updating the current
    // buffer. (old contents are lost)

    fn modify(&mut self) {
        if let Some(hist_idx) = self.hist_curs {
            self.buffer.clear();
            self.buffer.extend_from_slice(self.history[hist_idx as usize].borrow());
            self.hist_curs = None;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Manipulating cursor

    fn inc_cursor(&mut self) {
        let cur = min(self.line_len(), self.cursor + 1);
        self.move_cursor(cur);
    }

    fn dec_cursor(&mut self) {
        let cur = max(0, self.cursor - 1);
        self.move_cursor(cur);
    }

    // NOTE: This doesn't do bounds checking! Use dec_cursor() and inc_cursor().
    // move_cursor(0) should always be safe.
    fn move_cursor(&mut self, cursor : i32) {
        self.cursor = cursor;

        if self.line_len() + 1 < self.width {
            self.scroll = 0;
        } else {
            let scrolloff = { if self.width < 2 * SCROLLOFF + 1 { 0 } else { SCROLLOFF } };

            let left_end  = self.scroll;
            let right_end = self.scroll + self.width;

            if cursor - scrolloff < left_end {
                self.scroll = max(0, cursor - scrolloff);
            } else if cursor + scrolloff >= right_end {
                self.scroll = min(// +1 because cursor should be visible, i.e.
                                  // right_end > cursor should hold after this
                                  max(0, cursor + 1 + scrolloff - self.width),
                                  // +1 because cursor goes one more character
                                  // after the buffer, to be able to add chars
                                  max(0, self.line_len() + 1 - self.width));
            }
        }
    }
}
<commit_msg>improve C-w behavior. it now works more like vim's insert mode C-w.<commit_after>use std::borrow::Borrow;
use std::cmp::{max, min};
use std::mem;

use rustbox::keyboard::Key;
use rustbox::{RustBox};

use tui::style;
use tui::termbox;
use tui::widget::{WidgetRet};

// TODO: Make these settings
const SCROLLOFF : i32 = 5;
const HIST_SIZE : usize = 30;

pub struct TextField {
    /// The message that's currently being edited (not yet sent)
    buffer : Vec<char>,

    /// Cursor in currently shown line
    cursor : i32,

    /// Horizontal scroll
    scroll : i32,

    /// Width of the widget
    width : i32,

    /// A history of sent messages/commands. Once added messages are never
    /// modified. A modification attempt should result in a new buffer with a
    /// copy of the vector in history. (old contents of the buffer will be lost)
    history : Vec<Vec<char>>,

    /// Only available when moving in `history` vector.
    /// INVARIANT: When available, it's a valid index in history.
    hist_curs : Option<i32>,
}

impl TextField {
    pub fn new(width : i32) -> TextField {
        TextField {
            buffer: Vec::with_capacity(512),
            cursor: 0,
            scroll: 0,
            width: width,
            history: Vec::with_capacity(HIST_SIZE),
            hist_curs: None,
        }
    }

    pub fn resize(&mut self, width : i32, _ : i32) {
        self.width = width;
        let cursor = self.cursor;
        self.move_cursor(cursor);
    }

    pub fn draw(&self, _ : &RustBox, pos_x : i32, pos_y : i32) {
        // draw text
        let line_borrow : &[char] = {
            if let Some(hist_curs) = self.hist_curs {
                self.history[hist_curs as usize].borrow()
            } else {
                self.buffer.borrow()
            }
        };

        let slice : &[char] =
            &line_borrow[ self.scroll as usize ..
                          min(line_borrow.len(), (self.scroll + self.width) as usize) ];

        termbox::print_chars(pos_x, pos_y, style::USER_MSG.fg, style::USER_MSG.bg, slice);

        // draw cursor
        termbox::print_char(pos_x + self.cursor - self.scroll, pos_y,
                            style::CURSOR.fg, style::CURSOR.bg,
                            *line_borrow.get(self.cursor as usize).unwrap_or(&' '));
    }

    pub fn keypressed(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Char(ch) => {
                self.modify();
                self.buffer.insert(self.cursor as usize, ch);
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Backspace => {
                if self.cursor > 0 {
                    self.modify();
                    self.buffer.remove(self.cursor as usize - 1);
                    self.dec_cursor();
                }
                WidgetRet::KeyHandled
            },

            Key::Ctrl(ch) => {
                if ch == 'a' {
                    self.move_cursor(0);
                    WidgetRet::KeyHandled
                }

                else if ch == 'e' {
                    let cur = self.line_len();
                    self.move_cursor(cur);
                    WidgetRet::KeyHandled
                }

                else if ch == 'k' {
                    self.modify();
                    self.buffer.drain(self.cursor as usize ..);
                    WidgetRet::KeyHandled
                }

                else if ch == 'w' {
                    self.consume_word_before_curs();
                    WidgetRet::KeyHandled
                }

                else {
                    WidgetRet::KeyIgnored
                }
            },

            Key::Left => {
                self.dec_cursor();
                WidgetRet::KeyHandled
            },

            Key::Right => {
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Enter => {
                let ret = mem::replace(&mut self.buffer, Vec::new());
                if self.history.len() == HIST_SIZE {
                    let mut reuse = self.history.remove(0);
                    reuse.clear();
                    reuse.extend_from_slice(&ret);
                    self.history.push(reuse);
                } else {
                    self.history.push(ret.clone());
                }
                self.move_cursor(0);
                if ret.len() == 0 {
                    WidgetRet::KeyHandled
                } else {
                    WidgetRet::Input(ret)
                }
            },

            ////////////////////////////////////////////////////////////////////
            // Scrolling in history

            Key::Up => {
                match self.hist_curs {
                    Some(hist_curs) if hist_curs > 0 => {
                        self.hist_curs = Some(hist_curs - 1);
                        let cur = self.line_len();
                        self.move_cursor(cur);
                    },
                    Some(_) => {},
                    None => {
                        if !self.history.is_empty() {
                            self.hist_curs = Some((self.history.len() as i32) - 1);
                            let cur = self.line_len();
                            self.move_cursor(cur);
                        }
                    }
                }
                WidgetRet::KeyHandled
            },

            Key::Down => {
                match self.hist_curs {
                    Some(hist_curs) => {
                        if (hist_curs as usize) < self.history.len() - 1 {
                            self.hist_curs = Some(hist_curs + 1);
                            let cur = self.line_len();
                            self.move_cursor(cur);
                        } else {
                            self.hist_curs = None;
                            let cur = self.line_len();
                            self.move_cursor(cur);
                        }
                    },
                    None => {}
                }
                WidgetRet::KeyHandled
            },

            ////////////////////////////////////////////////////////////////////

            _ => WidgetRet::KeyIgnored,
        }
    }

    fn consume_word_before_curs(&mut self) {
        // No modifications can happen if the scroll is at the beginning
        if self.cursor == 0 {
            return;
        }

        self.modify();

        let char = self.buffer[(self.cursor - 1) as usize];

        // Try to imitate vim's behaviour here.
        if char.is_whitespace() {
            self.consume_before(|c| c.is_whitespace());
        }

        else if char.is_alphanumeric() {
            self.consume_before(|c| c.is_alphanumeric());
        }

        else {
            self.consume_before(|c| !c.is_alphanumeric());
        }
    }

    fn consume_before<F>(&mut self, f : F) where F : Fn(char) -> bool {
        let end_range = self.cursor as usize;
        let mut begin_range = self.cursor - 1;
        while begin_range >= 0 && f(self.buffer[begin_range as usize]) {
            begin_range -= 1;
        }
        self.buffer.drain(((begin_range + 1) as usize) .. end_range);
        self.move_cursor(begin_range + 1);
    }

    #[inline]
    fn line_len(&self) -> i32 {
        if let Some(hist_curs) = self.hist_curs {
            self.history[hist_curs as usize].len() as i32
        } else {
            self.buffer.len() as i32
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // We never modify history, so if the user attempts at a modification, we
    // just make the history entry current message by updating the current
    // buffer. (old contents are lost)

    fn modify(&mut self) {
        if let Some(hist_idx) = self.hist_curs {
            self.buffer.clear();
            self.buffer.extend_from_slice(self.history[hist_idx as usize].borrow());
            self.hist_curs = None;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Manipulating cursor

    fn inc_cursor(&mut self) {
        let cur = min(self.line_len(), self.cursor + 1);
        self.move_cursor(cur);
    }

    fn dec_cursor(&mut self) {
        let cur = max(0, self.cursor - 1);
        self.move_cursor(cur);
    }

    // NOTE: This doesn't do bounds checking! Use dec_cursor() and inc_cursor().
    // move_cursor(0) should always be safe.
    fn move_cursor(&mut self, cursor : i32) {
        self.cursor = cursor;

        if self.line_len() + 1 < self.width {
            self.scroll = 0;
        } else {
            let scrolloff = { if self.width < 2 * SCROLLOFF + 1 { 0 } else { SCROLLOFF } };

            let left_end  = self.scroll;
            let right_end = self.scroll + self.width;

            if cursor - scrolloff < left_end {
                self.scroll = max(0, cursor - scrolloff);
            } else if cursor + scrolloff >= right_end {
                self.scroll = min(// +1 because cursor should be visible, i.e.
                                  // right_end > cursor should hold after this
                                  max(0, cursor + 1 + scrolloff - self.width),
                                  // +1 because cursor goes one more character
                                  // after the buffer, to be able to add chars
                                  max(0, self.line_len() + 1 - self.width));
            }
        }
    }
}
<|endoftext|>


<commit_before>// `cargo test --benches` and `#[feature(test)]` work only in nightly
#![cfg(rustc_nightly)]
#![cfg(feature = "bytes")]
#![feature(test)]

extern crate test;

use bytes::Bytes;
use perftest_bytes::messages;
use protobuf::Message;

fn make_string_of_len(len: usize) -> String {
    let mut s = String::new();
    for i in 0..len {
        write!(s, "{}", i % 10).expect("unreachable");
    }
    s
}

fn make_repeated(len: usize) -> Vec<u8> {
    let mut m = messages::TestMessage::new();

    for i in 0..100 {
        m.sr.push(make_string_of_len(i % len));
        m.br.push(make_string_of_len((i + len / 2) % len).into_bytes());
    }

    m.write_to_bytes().expect("write")
}

#[bench]
fn parse_repeated_small_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_small_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_regular(b: &mut test::Bencher) {
    let bs = make_repeated(300);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(300));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_regular(b: &mut test::Bencher) {
    let bs = make_repeated(3000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(3000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}
<commit_msg>Fix compilation<commit_after>// `cargo test --benches` and `#[feature(test)]` work only in nightly
#![cfg(rustc_nightly)]
#![cfg(feature = "bytes")]
#![feature(test)]

extern crate test;

use std::fmt::Write as _;
use bytes::Bytes;
use perftest_bytes::messages;
use protobuf::Message;

fn make_string_of_len(len: usize) -> String {
    let mut s = String::new();
    for i in 0..len {
        write!(s, "{}", i % 10).expect("unreachable");
    }
    s
}

fn make_repeated(len: usize) -> Vec<u8> {
    let mut m = messages::TestMessage::new();

    for i in 0..100 {
        m.sr.push(make_string_of_len(i % len));
        m.br.push(make_string_of_len((i + len / 2) % len).into_bytes());
    }

    m.write_to_bytes().expect("write")
}

#[bench]
fn parse_repeated_small_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_small_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_regular(b: &mut test::Bencher) {
    let bs = make_repeated(300);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_medium_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(300));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_regular(b: &mut test::Bencher) {
    let bs = make_repeated(3000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_large_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(3000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_regular(b: &mut test::Bencher) {
    let bs = make_repeated(30000);
    b.iter(|| messages::TestMessage::parse_from_bytes(&bs).expect("parse"))
}

#[bench]
fn parse_repeated_huge_bytes(b: &mut test::Bencher) {
    let bs = Bytes::from(make_repeated(30000));
    b.iter(|| messages::TestMessageWithBytes::parse_from_tokio_bytes(&bs).expect("parse"))
}
<|endoftext|>


<commit_before>#![feature(trace_macros)]
#![recursion_limit = "256"]
// trace_macros!(true);

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate asn1_cereal;
#[macro_use]
extern crate nom;

use proc_macro::TokenStream;

use ::tag::parse_tag;
use ::alias::{ber_alias_serialize, ber_alias_deserialize};
use ::seq_of::{ber_sequence_of_serialize, ber_sequence_of_deserialize};
use ::seq::{ber_sequence_serialize, ber_sequence_deserialize};
use ::choice::{ber_choice_serialize, ber_choice_deserialize};

mod tag;
mod seq;
mod seq_of;
mod alias;
mod choice;

#[proc_macro_derive(Asn1Info, attributes(asn1))]
pub fn asn1_info(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  // Tag and asn1 type for this rust type.
  let mut tag = quote!(None);
  let mut asn1_type = ast.ident.as_ref().to_owned();
  let mut _logging = false;

  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => _logging = true,
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "tag" => tag = parse_tag(value.as_bytes()).unwrap().1,
              "asn1_type" => asn1_type = value.clone(),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  // Used in the quasi-quotation below as `#name`
  let name = &ast.ident;

  // Helper is provided for handling complex generic types correctly and effortlessly
  let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

  let derived = quote! {
    impl #impl_generics ::asn1_cereal::Asn1Info for #name #ty_generics #where_clause {
      fn asn1_tag() -> Option<::asn1_cereal::tag::Tag> {
        #tag
      }

      fn asn1_type() -> ::asn1_cereal::tag::Type {
        #asn1_type.to_owned()
      }
    }
  };

  derived.to_string().parse().expect("Failure parsing derived impl")
}

fn logging_enabled(ast: &syn::MacroInput) -> bool {
  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => return true,
          _ => (),
        };
      }
    }
  }
  false
}

#[proc_macro_derive(BerSerialize, attributes(asn1))]
pub fn ber_serialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).unwrap();

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_serialize(&ast),
      "alias" => ber_alias_serialize(&ast),
      "choice" => ber_choice_serialize(&ast),
      "seq" | "sequence" => ber_sequence_serialize(&ast),
      _ => panic!("Unknown serialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_serialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_serialize(&ast)
        } else {
          ber_sequence_serialize(&ast)
        }
      },
      syn::Body::Struct(syn::VariantData::Struct(_fields)) => {
        ber_sequence_serialize(&ast)
      },
      _ => unimplemented!(),
    }
  };

  derived.to_string().parse().expect("Failure parsing derived impl")
}

#[proc_macro_derive(BerDeserialize, attributes(asn1))]
pub fn ber_deserialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_deserialize(&ast),
      "alias" => ber_alias_deserialize(&ast),
      "choice" => ber_choice_deserialize(&ast),
      "seq" | "sequence" => ber_sequence_deserialize(&ast),
      _ => panic!("Unknown deserialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_deserialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_deserialize(&ast)
        } else {
          ber_sequence_deserialize(&ast)
        }
      },
      syn::Body::Struct(syn::VariantData::Struct(_fields)) => {
        ber_sequence_deserialize(&ast)
      },
      _ => unimplemented!(),
    }
  };

  derived.to_string().parse().expect("Failure parsing derived impl")
}

#[test]
fn test() {
}
<commit_msg>Remove trace_macros<commit_after>// #![feature(trace_macros)]
#![recursion_limit = "256"]
// trace_macros!(true);

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate asn1_cereal;
#[macro_use]
extern crate nom;

use proc_macro::TokenStream;

use ::tag::parse_tag;
use ::alias::{ber_alias_serialize, ber_alias_deserialize};
use ::seq_of::{ber_sequence_of_serialize, ber_sequence_of_deserialize};
use ::seq::{ber_sequence_serialize, ber_sequence_deserialize};
use ::choice::{ber_choice_serialize, ber_choice_deserialize};

mod tag;
mod seq;
mod seq_of;
mod alias;
mod choice;

#[proc_macro_derive(Asn1Info, attributes(asn1))]
pub fn asn1_info(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  // Tag and asn1 type for this rust type.
  let mut tag = quote!(None);
  let mut asn1_type = ast.ident.as_ref().to_owned();
  let mut _logging = false;

  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => _logging = true,
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "tag" => tag = parse_tag(value.as_bytes()).unwrap().1,
              "asn1_type" => asn1_type = value.clone(),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  // Used in the quasi-quotation below as `#name`
  let name = &ast.ident;

  // Helper is provided for handling complex generic types correctly and effortlessly
  let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

  let derived = quote! {
    impl #impl_generics ::asn1_cereal::Asn1Info for #name #ty_generics #where_clause {
      fn asn1_tag() -> Option<::asn1_cereal::tag::Tag> {
        #tag
      }

      fn asn1_type() -> ::asn1_cereal::tag::Type {
        #asn1_type.to_owned()
      }
    }
  };

  derived.to_string().parse().expect("Failure parsing derived impl")
}

fn logging_enabled(ast: &syn::MacroInput) -> bool {
  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => return true,
          _ => (),
        };
      }
    }
  }
  false
}

#[proc_macro_derive(BerSerialize, attributes(asn1))]
pub fn ber_serialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).unwrap();

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_serialize(&ast),
      "alias" => ber_alias_serialize(&ast),
      "choice" => ber_choice_serialize(&ast),
      "seq" | "sequence" => ber_sequence_serialize(&ast),
      _ => panic!("Unknown serialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_serialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_serialize(&ast)
        } else {
          ber_sequence_serialize(&ast)
        }
      },
      syn::Body::Struct(syn::VariantData::Struct(_fields)) => {
        ber_sequence_serialize(&ast)
      },
      _ => unimplemented!(),
    }
  };

  derived.to_string().parse().expect("Failure parsing derived impl")
}

#[proc_macro_derive(BerDeserialize, attributes(asn1))]
pub fn ber_deserialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_deserialize(&ast),
      "alias" => ber_alias_deserialize(&ast),
      "choice" => ber_choice_deserialize(&ast),
      "seq" | "sequence" => ber_sequence_deserialize(&ast),
      _ => panic!("Unknown deserialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_deserialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_deserialize(&ast)
        } else {
          ber_sequence_deserialize(&ast)
        }
      },
      syn::Body::Struct(syn::VariantData::Struct(_fields)) => {
        ber_sequence_deserialize(&ast)
      },
      _ => unimplemented!(),
    }
  };

  derived.to_string().parse().expect("Failure parsing derived impl")
}

#[test]
fn test() {
}
<|endoftext|>


<commit_before>//! Compare libc's CMSG(3) family of functions against the actual C macros, for
//! various inputs.

extern crate libc;

#[cfg(unix)]
mod t {

    use libc::{self, c_uchar, c_uint, c_void, cmsghdr, msghdr};
    use std::mem;

    extern "C" {
        pub fn cmsg_firsthdr(msgh: *const msghdr) -> *mut cmsghdr;
        pub fn cmsg_nxthdr(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr;
        pub fn cmsg_space(length: c_uint) -> usize;
        pub fn cmsg_len(length: c_uint) -> usize;
        pub fn cmsg_data(cmsg: *const cmsghdr) -> *mut c_uchar;
    }

    #[test]
    fn test_cmsg_data() {
        for l in 0..128 {
            let pcmsghdr = l as *const cmsghdr;
            unsafe {
                assert_eq!(libc::CMSG_DATA(pcmsghdr), cmsg_data(pcmsghdr));
            }
        }
    }

    #[test]
    fn test_cmsg_firsthdr() {
        let mut mhdr: msghdr = unsafe { mem::zeroed() };
        mhdr.msg_control = 0xdeadbeef as *mut c_void;
        let pmhdr = &mhdr as *const msghdr;
        for l in 0..128 {
            mhdr.msg_controllen = l;
            unsafe {
                assert_eq!(libc::CMSG_FIRSTHDR(pmhdr), cmsg_firsthdr(pmhdr));
            }
        }
    }

    #[test]
    fn test_cmsg_len() {
        for l in 0..128 {
            unsafe {
                assert_eq!(libc::CMSG_LEN(l) as usize, cmsg_len(l));
            }
        }
    }

    // Skip on sparc64
    // https://github.com/rust-lang/libc/issues/1239
    #[cfg(not(target_arch = "sparc64"))]
    #[test]
    fn test_cmsg_nxthdr() {
        use std::ptr;

        let mut buffer = [0u8; 256];
        let mut mhdr: msghdr = unsafe { mem::zeroed() };
        let pmhdr = &mhdr as *const msghdr;
        for start_ofs in 0..64 {
            let pcmsghdr = &mut buffer[start_ofs] as *mut u8 as *mut cmsghdr;
            mhdr.msg_control = pcmsghdr as *mut c_void;
            mhdr.msg_controllen = (160 - start_ofs) as _;
            for cmsg_len in 0..64 {
                for next_cmsg_len in 0..32 {
                    for i in buffer[start_ofs..].iter_mut() {
                        *i = 0;
                    }
                    unsafe {
                        (*pcmsghdr).cmsg_len = cmsg_len;
                        let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
                        let next = cmsg_nxthdr(pmhdr, pcmsghdr);
                        assert_eq!(libc_next, next);

                        if libc_next != ptr::null_mut() {
                            (*libc_next).cmsg_len = next_cmsg_len;
                            let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
                            let next = cmsg_nxthdr(pmhdr, pcmsghdr);
                            assert_eq!(libc_next, next);
                        }
                    }
                }
            }
        }
    }

    #[test]
    fn test_cmsg_space() {
        unsafe {
            for l in 0..128 {
                assert_eq!(libc::CMSG_SPACE(l) as usize, cmsg_space(l));
            }
        }
    }
}
<commit_msg>fix cmsg test proposal<commit_after>//! Compare libc's CMSG(3) family of functions against the actual C macros, for
//! various inputs.

extern crate libc;

#[cfg(unix)]
mod t {

    use libc::{self, c_uchar, c_uint, c_void, cmsghdr, msghdr};
    use std::mem;

    extern "C" {
        pub fn cmsg_firsthdr(msgh: *const msghdr) -> *mut cmsghdr;
        // see below
        #[cfg(not(target_arch = "sparc64"))]
        pub fn cmsg_nxthdr(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr;
        pub fn cmsg_space(length: c_uint) -> usize;
        pub fn cmsg_len(length: c_uint) -> usize;
        pub fn cmsg_data(cmsg: *const cmsghdr) -> *mut c_uchar;
    }

    #[test]
    fn test_cmsg_data() {
        for l in 0..128 {
            let pcmsghdr = l as *const cmsghdr;
            unsafe {
                assert_eq!(libc::CMSG_DATA(pcmsghdr), cmsg_data(pcmsghdr));
            }
        }
    }

    #[test]
    fn test_cmsg_firsthdr() {
        let mut mhdr: msghdr = unsafe { mem::zeroed() };
        mhdr.msg_control = 0xdeadbeef as *mut c_void;
        let pmhdr = &mhdr as *const msghdr;
        for l in 0..128 {
            mhdr.msg_controllen = l;
            unsafe {
                assert_eq!(libc::CMSG_FIRSTHDR(pmhdr), cmsg_firsthdr(pmhdr));
            }
        }
    }

    #[test]
    fn test_cmsg_len() {
        for l in 0..128 {
            unsafe {
                assert_eq!(libc::CMSG_LEN(l) as usize, cmsg_len(l));
            }
        }
    }

    // Skip on sparc64
    // https://github.com/rust-lang/libc/issues/1239
    #[cfg(not(target_arch = "sparc64"))]
    #[test]
    fn test_cmsg_nxthdr() {
        use std::ptr;

        let mut buffer = [0u8; 256];
        let mut mhdr: msghdr = unsafe { mem::zeroed() };
        let pmhdr = &mhdr as *const msghdr;
        for start_ofs in 0..64 {
            let pcmsghdr = &mut buffer[start_ofs] as *mut u8 as *mut cmsghdr;
            mhdr.msg_control = pcmsghdr as *mut c_void;
            mhdr.msg_controllen = (160 - start_ofs) as _;
            for cmsg_len in 0..64 {
                for next_cmsg_len in 0..32 {
                    for i in buffer[start_ofs..].iter_mut() {
                        *i = 0;
                    }
                    unsafe {
                        (*pcmsghdr).cmsg_len = cmsg_len;
                        let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
                        let next = cmsg_nxthdr(pmhdr, pcmsghdr);
                        assert_eq!(libc_next, next);

                        if libc_next != ptr::null_mut() {
                            (*libc_next).cmsg_len = next_cmsg_len;
                            let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
                            let next = cmsg_nxthdr(pmhdr, pcmsghdr);
                            assert_eq!(libc_next, next);
                        }
                    }
                }
            }
        }
    }

    #[test]
    fn test_cmsg_space() {
        unsafe {
            for l in 0..128 {
                assert_eq!(libc::CMSG_SPACE(l) as usize, cmsg_space(l));
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use basetypes::*;
use chess_move::MoveStack;
use tt::*;
use position::Position;

pub enum Command {
    Search {
        search_id: usize,
        position: Position,
        depth: u8,
        lower_bound: Value,
        upper_bound: Value,
    },
    Stop,
    Exit,
}

pub enum Report {
    Progress {
        search_id: usize,
        searched_nodes: NodeCount,
        depth: u8,
    },
    Done {
        search_id: usize,
        searched_nodes: NodeCount,
        value: Option<Value>,
    },
}

pub fn run_deepening(tt: Arc<TranspositionTable>,
                     commands: Receiver<Command>,
                     reports: Sender<Report>) {
    let (slave_commands_tx, slave_commands_rx) = channel();
    let (slave_reports_tx, slave_reports_rx) = channel();
    let slave = thread::spawn(move || {
        run(tt, slave_commands_rx, slave_reports_tx);
    });
    let mut pending_command = None;
    loop {
        // If there is a pending command, we take it, otherwise we
        // block and wait to receive a new one.
        let command = match pending_command.take() {
            Some(cmd) => cmd,
            None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
        };

        match command {
            Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                let mut searched_nodes_final = 0;
                let mut value_final = None;
                'depthloop: for n in 1..(depth + 1) {
                    slave_commands_tx.send(Command::Search {
                                         search_id: n as usize,
                                         position: position.clone(),
                                         depth: n,
                                         lower_bound: lower_bound,
                                         upper_bound: upper_bound,
                                     })
                                     .unwrap();
                    loop {
                        match slave_reports_rx.recv().unwrap() {
                            Report::Progress { searched_nodes, .. } => {
                                reports.send(Report::Progress {
                                           search_id: search_id,
                                           searched_nodes: searched_nodes_final + searched_nodes,
                                           depth: n,
                                       })
                                       .ok();
                                if pending_command.is_none() {
                                    pending_command = match commands.try_recv() {
                                        Ok(cmd) => {
                                            slave_commands_tx.send(Command::Stop).unwrap();
                                            Some(cmd)
                                        }
                                        _ => None,
                                    }
                                }
                            }
                            Report::Done { searched_nodes, value, .. } => {
                                searched_nodes_final += searched_nodes;
                                if n == depth {
                                    value_final = value;
                                }
                                if pending_command.is_some() {
                                    break 'depthloop;
                                }
                                break;
                            }
                        }
                    }
                }
                reports.send(Report::Done {
                           search_id: search_id,
                           searched_nodes: searched_nodes_final,
                           value: value_final,
                       })
                       .ok();
            }
            Command::Stop => {
                slave_commands_tx.send(Command::Stop).unwrap();
                continue;
            }
            Command::Exit => {
                slave_commands_tx.send(Command::Exit).unwrap();
                break;
            }
        }
    }
    slave.join().unwrap();
}

pub fn run(tt: Arc<TranspositionTable>, commands: Receiver<Command>, reports: Sender<Report>) {
    thread_local!(
        static MOVE_STACK: UnsafeCell<MoveStack> = UnsafeCell::new(MoveStack::new())
    );
    MOVE_STACK.with(|s| {
        let mut move_stack = unsafe { &mut *s.get() };
        let mut pending_command = None;
        loop {
            // If there is a pending command, we take it, otherwise we
            // block and wait to receive a new one.
            let command = match pending_command.take() {
                Some(cmd) => cmd,
                None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
            };

            match command {
                Command::Search { search_id, mut position, depth, lower_bound, upper_bound } => {
                    let mut reported_nodes = 0;
                    let mut unreported_nodes = 0;
                    let value = search(&tt,
                                       &mut position,
                                       move_stack,
                                       &mut unreported_nodes,
                                       &mut |n| {
                                           reported_nodes += n;
                                           reports.send(Report::Progress {
                                                      search_id: search_id,
                                                      searched_nodes: reported_nodes,
                                                      depth: depth,
                                                  })
                                                  .ok();
                                           match commands.try_recv() {
                                               Ok(x) => {
                                                   pending_command = Some(x);
                                                   Err(TerminatedSearch)
                                               }
                                               _ => Ok(()),
                                           }
                                       },
                                       lower_bound,
                                       upper_bound,
                                       depth)
                                    .ok();
                    reported_nodes += unreported_nodes;
                    reports.send(Report::Progress {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               depth: depth,
                           })
                           .ok();
                    reports.send(Report::Done {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               value: value,
                           })
                           .ok();
                    move_stack.clear();
                }
                Command::Stop => continue,
                Command::Exit => break,
            }
        }
    })
}

// Represents a terminated search condition.
struct TerminatedSearch;

// Helper function for `run()`. It implements the principal variation
// search algorithm. When returning `Err(TerminatedSearch)`, this
// function may leave un-restored move lists in `moves`.
fn search(tt: &TranspositionTable,
          p: &mut Position,
          moves: &mut MoveStack,
          nc: &mut NodeCount,
          report: &mut FnMut(NodeCount) -> Result<(), TerminatedSearch>,
          mut alpha: Value, // lower bound
          beta: Value, // upper bound
          depth: u8)
          -> Result<Value, TerminatedSearch> {
    assert!(alpha < beta);
    if depth == 0 {
        // On leaf nodes, do quiescence search.
        let (value, nodes) = p.evaluate_quiescence(alpha, beta, None);
        *nc += nodes;
        Ok(value)
    } else {
        // Consult the transposition table.
        let hash_move16 = if let Some(entry) = tt.probe(p.hash()) {
            if entry.depth() >= depth {
                let value = entry.value();
                let bound = entry.bound();
                if bound == BOUND_EXACT {
                    return Ok(value);
                }
                if bound == BOUND_LOWER && value >= beta {
                    return Ok(beta);
                }
                if bound == BOUND_UPPER && value <= alpha {
                    return Ok(alpha);
                }
            }
            entry.move16()
        } else {
            0
        };

        moves.save();

        if hash_move16 != 0 {
            if let Some(m) = p.try_move_digest(hash_move16) {
                moves.push(m);
            }
        }
        let mut generated = false;

        let mut bound_type = BOUND_UPPER;
        let mut move16 = 0;
        let mut no_moves_yet = true;
        loop {
            // TODO: This is ugly, and probably inefficient.
            let m = match moves.remove_best_move() {
                None if generated => break,
                None => {
                    p.generate_moves(moves);
                    moves.remove_move(hash_move16);
                    generated = true;
                    continue;
                }
                Some(x) => x,
            };

            if p.do_move(m) {
                // From time to time, we report how many nodes had
                // been searched since the last report. This also
                // gives an opportunity for the search to be
                // terminated.
                *nc += 1;
                if *nc > NODE_COUNT_REPORT_INTERVAL {
                    try!(report(*nc));
                    *nc = 0;
                }

                let mut value = if no_moves_yet {
                    // The first move we analyze with a fully open
                    // window (alpha, beta).
                    -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that
                    // they are not better than our current best
                    // move. For this purpose we analyze them with a
                    // null window (alpha, alpha + 1). This is faster
                    // than a full window search. Only when we are
                    // certain that the move is better than our
                    // current best move, we do a full-window search.
                    match -try!(search(tt, p, moves, nc, report, -alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1)),
                    }
                };

                // A checkmate in fewer moves is better.
                if value > 20000 {
                    value -= 1;
                }
                if value < -20000 {
                    value += 1;
                }

                no_moves_yet = false;
                p.undo_move();

                if value >= beta {
                    // This move is too good, so that the opponent
                    // will not allow this line of play to
                    // happen. Therefore we can stop here.
                    alpha = beta;
                    bound_type = BOUND_LOWER;
                    move16 = m.digest();
                    break;
                }
                if value > alpha {
                    // We found ourselves a new best move.
                    alpha = value;
                    bound_type = BOUND_EXACT;
                    move16 = m.digest();
                }
            }
        }
        moves.restore();
        if no_moves_yet {
            // No legal moves -- this is a final position.
            alpha = p.evaluate_final();
            bound_type = BOUND_EXACT;
        }
        // TODO: Do not store values with too small `depth`.
        tt.store(p.hash(),
                 EntryData::new(alpha, bound_type, depth, move16, 0));
        Ok(alpha)
    }
}

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

#[cfg(test)]
mod tests {
    use super::search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let mut p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -30000,
                           30000,
                           2)
                        .ok()
                        .unwrap();
        assert!(value < -300);
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -30000,
                           30000,
                           4)
                        .ok()
                        .unwrap();
        assert!(value >= 20000);
    }
}
<commit_msg>consult TT before doing qsearch<commit_after>use std::thread;
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use basetypes::*;
use chess_move::MoveStack;
use tt::*;
use position::Position;

pub enum Command {
    Search {
        search_id: usize,
        position: Position,
        depth: u8,
        lower_bound: Value,
        upper_bound: Value,
    },
    Stop,
    Exit,
}

pub enum Report {
    Progress {
        search_id: usize,
        searched_nodes: NodeCount,
        depth: u8,
    },
    Done {
        search_id: usize,
        searched_nodes: NodeCount,
        value: Option<Value>,
    },
}

pub fn run_deepening(tt: Arc<TranspositionTable>,
                     commands: Receiver<Command>,
                     reports: Sender<Report>) {
    let (slave_commands_tx, slave_commands_rx) = channel();
    let (slave_reports_tx, slave_reports_rx) = channel();
    let slave = thread::spawn(move || {
        run(tt, slave_commands_rx, slave_reports_tx);
    });
    let mut pending_command = None;
    loop {
        // If there is a pending command, we take it, otherwise we
        // block and wait to receive a new one.
        let command = match pending_command.take() {
            Some(cmd) => cmd,
            None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
        };

        match command {
            Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                let mut searched_nodes_final = 0;
                let mut value_final = None;
                'depthloop: for n in 1..(depth + 1) {
                    slave_commands_tx.send(Command::Search {
                                         search_id: n as usize,
                                         position: position.clone(),
                                         depth: n,
                                         lower_bound: lower_bound,
                                         upper_bound: upper_bound,
                                     })
                                     .unwrap();
                    loop {
                        match slave_reports_rx.recv().unwrap() {
                            Report::Progress { searched_nodes, .. } => {
                                reports.send(Report::Progress {
                                           search_id: search_id,
                                           searched_nodes: searched_nodes_final + searched_nodes,
                                           depth: n,
                                       })
                                       .ok();
                                if pending_command.is_none() {
                                    pending_command = match commands.try_recv() {
                                        Ok(cmd) => {
                                            slave_commands_tx.send(Command::Stop).unwrap();
                                            Some(cmd)
                                        }
                                        _ => None,
                                    }
                                }
                            }
                            Report::Done { searched_nodes, value, .. } => {
                                searched_nodes_final += searched_nodes;
                                if n == depth {
                                    value_final = value;
                                }
                                if pending_command.is_some() {
                                    break 'depthloop;
                                }
                                break;
                            }
                        }
                    }
                }
                reports.send(Report::Done {
                           search_id: search_id,
                           searched_nodes: searched_nodes_final,
                           value: value_final,
                       })
                       .ok();
            }
            Command::Stop => {
                slave_commands_tx.send(Command::Stop).unwrap();
                continue;
            }
            Command::Exit => {
                slave_commands_tx.send(Command::Exit).unwrap();
                break;
            }
        }
    }
    slave.join().unwrap();
}

pub fn run(tt: Arc<TranspositionTable>, commands: Receiver<Command>, reports: Sender<Report>) {
    thread_local!(
        static MOVE_STACK: UnsafeCell<MoveStack> = UnsafeCell::new(MoveStack::new())
    );
    MOVE_STACK.with(|s| {
        let mut move_stack = unsafe { &mut *s.get() };
        let mut pending_command = None;
        loop {
            // If there is a pending command, we take it, otherwise we
            // block and wait to receive a new one.
            let command = match pending_command.take() {
                Some(cmd) => cmd,
                None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap(),
            };

            match command {
                Command::Search { search_id, mut position, depth, lower_bound, upper_bound } => {
                    let mut reported_nodes = 0;
                    let mut unreported_nodes = 0;
                    let value = search(&tt,
                                       &mut position,
                                       move_stack,
                                       &mut unreported_nodes,
                                       &mut |n| {
                                           reported_nodes += n;
                                           reports.send(Report::Progress {
                                                      search_id: search_id,
                                                      searched_nodes: reported_nodes,
                                                      depth: depth,
                                                  })
                                                  .ok();
                                           match commands.try_recv() {
                                               Ok(x) => {
                                                   pending_command = Some(x);
                                                   Err(TerminatedSearch)
                                               }
                                               _ => Ok(()),
                                           }
                                       },
                                       lower_bound,
                                       upper_bound,
                                       depth)
                                    .ok();
                    reported_nodes += unreported_nodes;
                    reports.send(Report::Progress {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               depth: depth,
                           })
                           .ok();
                    reports.send(Report::Done {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               value: value,
                           })
                           .ok();
                    move_stack.clear();
                }
                Command::Stop => continue,
                Command::Exit => break,
            }
        }
    })
}

// Represents a terminated search condition.
struct TerminatedSearch;

// Helper function for `run()`. It implements the principal variation
// search algorithm. When returning `Err(TerminatedSearch)`, this
// function may leave un-restored move lists in `moves`.
fn search(tt: &TranspositionTable,
          p: &mut Position,
          moves: &mut MoveStack,
          nc: &mut NodeCount,
          report: &mut FnMut(NodeCount) -> Result<(), TerminatedSearch>,
          mut alpha: Value, // lower bound
          beta: Value, // upper bound
          depth: u8)
          -> Result<Value, TerminatedSearch> {
    assert!(alpha < beta);

    // Consult the transposition table.
    let hash_move16 = if let Some(entry) = tt.probe(p.hash()) {
        if entry.depth() >= depth {
            let value = entry.value();
            let bound = entry.bound();
            if bound == BOUND_EXACT {
                return Ok(value);
            }
            if bound == BOUND_LOWER && value >= beta {
                return Ok(beta);
            }
            if bound == BOUND_UPPER && value <= alpha {
                return Ok(alpha);
            }
        }
        entry.move16()
    } else {
        0
    };

    if depth == 0 {
        // On leaf nodes, do quiescence search.
        let (value, nodes) = p.evaluate_quiescence(alpha, beta, None);
        *nc += nodes;
        Ok(value)
    } else {
        moves.save();

        if hash_move16 != 0 {
            if let Some(m) = p.try_move_digest(hash_move16) {
                moves.push(m);
            }
        }
        let mut generated = false;

        let mut bound_type = BOUND_UPPER;
        let mut move16 = 0;
        let mut no_moves_yet = true;
        loop {
            // TODO: This is ugly, and probably inefficient.
            let m = match moves.remove_best_move() {
                None if generated => break,
                None => {
                    p.generate_moves(moves);
                    moves.remove_move(hash_move16);
                    generated = true;
                    continue;
                }
                Some(x) => x,
            };

            if p.do_move(m) {
                // From time to time, we report how many nodes had
                // been searched since the last report. This also
                // gives an opportunity for the search to be
                // terminated.
                *nc += 1;
                if *nc > NODE_COUNT_REPORT_INTERVAL {
                    try!(report(*nc));
                    *nc = 0;
                }

                let mut value = if no_moves_yet {
                    // The first move we analyze with a fully open
                    // window (alpha, beta).
                    -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that
                    // they are not better than our current best
                    // move. For this purpose we analyze them with a
                    // null window (alpha, alpha + 1). This is faster
                    // than a full window search. Only when we are
                    // certain that the move is better than our
                    // current best move, we do a full-window search.
                    match -try!(search(tt, p, moves, nc, report, -alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1)),
                    }
                };

                // A checkmate in fewer moves is better.
                if value > 20000 {
                    value -= 1;
                }
                if value < -20000 {
                    value += 1;
                }

                no_moves_yet = false;
                p.undo_move();

                if value >= beta {
                    // This move is too good, so that the opponent
                    // will not allow this line of play to
                    // happen. Therefore we can stop here.
                    alpha = beta;
                    bound_type = BOUND_LOWER;
                    move16 = m.digest();
                    break;
                }
                if value > alpha {
                    // We found ourselves a new best move.
                    alpha = value;
                    bound_type = BOUND_EXACT;
                    move16 = m.digest();
                }
            }
        }
        moves.restore();
        if no_moves_yet {
            // No legal moves -- this is a final position.
            alpha = p.evaluate_final();
            bound_type = BOUND_EXACT;
        }
        // TODO: Do not store values with too small `depth`.
        tt.store(p.hash(),
                 EntryData::new(alpha, bound_type, depth, move16, 0));
        Ok(alpha)
    }
}

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

#[cfg(test)]
mod tests {
    use super::search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let mut p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -30000,
                           30000,
                           2)
                        .ok()
                        .unwrap();
        assert!(value < -300);
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -30000,
                           30000,
                           4)
                        .ok()
                        .unwrap();
        assert!(value >= 20000);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::iter::Empty;
use std::sync::Arc;
use smallvec::SmallVec;

use device::Device;
use device::Queue;
use format::FormatDesc;
use image::Dimensions;
use image::sys::ImageCreationError;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::sys::Usage;
use image::traits::Image;
use image::traits::ImageContent;
use image::traits::ImageView;
use image::traits::IntoImage;
use image::traits::IntoImageView;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

/// Image whose purpose is to be used for read-only purposes. You can write to the image once,
/// but then you must only ever read from it. TODO: clarify because of blit operations
// TODO: type (2D, 3D, array, etc.) as template parameter
#[derive(Debug)]
pub struct ImmutableImage<F, A = Arc<StdMemoryPool>> where A: MemoryPool {
    image: UnsafeImage,
    view: UnsafeImageView,
    dimensions: Dimensions,
    memory: A::Alloc,
    format: F,
}

impl<F> ImmutableImage<F> {
    /// Builds a new immutable image.
    pub fn new<'a, I>(device: &Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
                      -> Result<Arc<ImmutableImage<F>>, ImageCreationError>
        where F: FormatDesc, I: IntoIterator<Item = QueueFamily<'a>>
    {
        let usage = Usage {
            transfer_source: true,  // for blits
            transfer_dest: true,
            sampled: true,
            .. Usage::none()
        };

        let queue_families = queue_families.into_iter().map(|f| f.id())
                                           .collect::<SmallVec<[u32; 4]>>();

        let (image, mem_reqs) = unsafe {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            try!(UnsafeImage::new(device, &usage, format.format(), dimensions.to_image_dimensions(),
                                  1, 1, sharing, false, false))
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }

        let view = unsafe {
            try!(UnsafeImageView::raw(&image, dimensions.to_view_type(), 0 .. image.mipmap_levels(),
                                      0 .. image.dimensions().array_layers()))
        };

        Ok(Arc::new(ImmutableImage {
            image: image,
            view: view,
            memory: mem,
            dimensions: dimensions,
            format: format,
        }))
    }
}

impl<F, A> ImmutableImage<F, A> where A: MemoryPool {
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> Dimensions {
        self.dimensions
    }
}

// FIXME: wrong
unsafe impl<F, A> IntoImage for Arc<ImmutableImage<F, A>>
    where F: 'static + Send + Sync, A: MemoryPool
{
    type Target = Self;

    #[inline]
    fn into_image(self) -> Self {
        self
    }
}

// FIXME: wrong
unsafe impl<F, A> IntoImageView for Arc<ImmutableImage<F, A>>
    where F: 'static + Send + Sync, A: MemoryPool
{
    type Target = Self;

    #[inline]
    fn into_image_view(self) -> Self {
        self
    }
}

unsafe impl<F, A> Image for ImmutableImage<F, A> where F: 'static + Send + Sync, A: MemoryPool {
    #[inline]
    fn inner(&self) -> &UnsafeImage {
        &self.image
    }

    #[inline]
    fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
        self.image.key()
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
        true        // FIXME:
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        // FIXME:
    }
}

unsafe impl<P, F, A> ImageContent<P> for ImmutableImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl<F: 'static, A> ImageView for ImmutableImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn parent(&self) -> &Image {
        self
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        self.dimensions
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}
<commit_msg>Add ImmutableImage::with_mipmaps<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::iter::Empty;
use std::sync::Arc;
use smallvec::SmallVec;

use device::Device;
use device::Queue;
use format::FormatDesc;
use image::Dimensions;
use image::MipmapsCount;
use image::sys::ImageCreationError;
use image::sys::Layout;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::sys::Usage;
use image::traits::Image;
use image::traits::ImageContent;
use image::traits::ImageView;
use image::traits::IntoImage;
use image::traits::IntoImageView;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

/// Image whose purpose is to be used for read-only purposes. You can write to the image once,
/// but then you must only ever read from it. TODO: clarify because of blit operations
// TODO: type (2D, 3D, array, etc.) as template parameter
#[derive(Debug)]
pub struct ImmutableImage<F, A = Arc<StdMemoryPool>> where A: MemoryPool {
    image: UnsafeImage,
    view: UnsafeImageView,
    dimensions: Dimensions,
    memory: A::Alloc,
    format: F,
}

impl<F> ImmutableImage<F> {
    /// Builds a new immutable image.
    // TODO: one mipmap is probably not a great default
    #[inline]
    pub fn new<'a, I>(device: &Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
                      -> Result<Arc<ImmutableImage<F>>, ImageCreationError>
        where F: FormatDesc, I: IntoIterator<Item = QueueFamily<'a>>
    {
        ImmutableImage::with_mipmaps(device, dimensions, format, MipmapsCount::One, queue_families)
    }

    /// Builds a new immutable image with the given number of mipmaps.
    pub fn with_mipmaps<'a, I, M>(device: &Arc<Device>, dimensions: Dimensions, format: F,
                                  mipmaps: M, queue_families: I)
                                  -> Result<Arc<ImmutableImage<F>>, ImageCreationError>
        where F: FormatDesc, I: IntoIterator<Item = QueueFamily<'a>>, M: Into<MipmapsCount>
    {
        let usage = Usage {
            transfer_source: true,  // for blits
            transfer_dest: true,
            sampled: true,
            .. Usage::none()
        };

        let queue_families = queue_families.into_iter().map(|f| f.id())
                                           .collect::<SmallVec<[u32; 4]>>();

        let (image, mem_reqs) = unsafe {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            try!(UnsafeImage::new(device, &usage, format.format(), dimensions.to_image_dimensions(),
                                  1, mipmaps, sharing, false, false))
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }

        let view = unsafe {
            try!(UnsafeImageView::raw(&image, dimensions.to_view_type(), 0 .. image.mipmap_levels(),
                                      0 .. image.dimensions().array_layers()))
        };

        Ok(Arc::new(ImmutableImage {
            image: image,
            view: view,
            memory: mem,
            dimensions: dimensions,
            format: format,
        }))
    }
}

impl<F, A> ImmutableImage<F, A> where A: MemoryPool {
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> Dimensions {
        self.dimensions
    }
}

// FIXME: wrong
unsafe impl<F, A> IntoImage for Arc<ImmutableImage<F, A>>
    where F: 'static + Send + Sync, A: MemoryPool
{
    type Target = Self;

    #[inline]
    fn into_image(self) -> Self {
        self
    }
}

// FIXME: wrong
unsafe impl<F, A> IntoImageView for Arc<ImmutableImage<F, A>>
    where F: 'static + Send + Sync, A: MemoryPool
{
    type Target = Self;

    #[inline]
    fn into_image_view(self) -> Self {
        self
    }
}

unsafe impl<F, A> Image for ImmutableImage<F, A> where F: 'static + Send + Sync, A: MemoryPool {
    #[inline]
    fn inner(&self) -> &UnsafeImage {
        &self.image
    }

    #[inline]
    fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
        self.image.key()
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
        true        // FIXME:
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        // FIXME:
    }
}

unsafe impl<P, F, A> ImageContent<P> for ImmutableImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl<F: 'static, A> ImageView for ImmutableImage<F, A>
    where F: 'static + Send + Sync, A: MemoryPool
{
    #[inline]
    fn parent(&self) -> &Image {
        self
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        self.dimensions
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> Layout {
        Layout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}
<|endoftext|>