<commit_before>#![crate_type = "lib"]
#![crate_name = "sharedbuffer"]

use std::sync::Arc;
use std::cmp;

use std::io;
use std::ops::Deref;
use std::io::{ErrorKind, Read, Seek, SeekFrom};

/* TODO: this would be better if we didn't indirect twice to the data
 * but that would require our own version of Arc and Vec... It shouldn't
 * be that bad but its just not important right now.
 */
#[derive(Eq,PartialEq,Clone,Debug)]
pub struct SharedReadBuffer {
  inner: Arc<Vec<u8>>,
  offset: usize, // lower limit of where we can look
  pos: usize,    // absolute position
  limit: usize   // absolute end
}

impl Deref for SharedReadBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl SharedReadBuffer {
    pub fn empty() -> SharedReadBuffer {
        SharedReadBuffer::new(Vec::new())
    }

  pub fn new(buffer: Vec<u8>) -> SharedReadBuffer {
    let lim = buffer.len();

    SharedReadBuffer {
      inner: Arc::new(buffer),
      offset: 0,
      pos: 0,
      limit: lim
    }
  }

  pub fn as_bytes(&self) -> &[u8] {
    &self.inner[self.pos..self.limit]
  }

  pub fn consume_slice(&mut self, length: usize) -> io::Result<SharedReadBuffer> {
    let next = self.slice(length);
    let _ = try!(self.seek(SeekFrom::Current(length as i64)));
    Ok(next)
  }

  pub fn consume_remaining(self) -> SharedReadBuffer {
    SharedReadBuffer {
        inner: self.inner,
        offset: self.pos,
        pos: self.pos,
        limit: self.limit
    }
  }

  pub fn slice(&self, length: usize) -> SharedReadBuffer {
    SharedReadBuffer {
      inner: self.inner.clone(),
      offset: self.pos,
      pos: self.pos,
      limit: cmp::min(self.limit, self.pos + length)
    }
  }

  pub fn len(&self) -> usize {
    self.limit - self.offset
  }

  pub fn remaining(&self) -> usize {
    self.limit - self.pos
  }

  pub fn pos(&self) -> usize {
    self.pos - self.offset
  }

  pub fn peak_reader<F,T>(&self, f: F) -> T
    where F: Fn(&mut SharedReadBuffer) -> T {
    let mut image = self.clone(); // TODO: make more efficient
    f(&mut image)
  }
}

impl io::Read for SharedReadBuffer {
  fn read(&mut self, buff: &mut [u8]) -> io::Result<usize> {
    let to_read = cmp::min(buff.len(), self.limit - self.pos);
    // copy the bytes
    unsafe {
      std::ptr::copy(self.inner.as_ptr(), buff.as_mut_ptr(), to_read);
    }
    self.pos += to_read;

    Ok(to_read)
  }
}

impl io::Seek for SharedReadBuffer {
  fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {

    let next_pos: i64 = match pos {
      SeekFrom::Start(p) => (self.offset as i64) + (p as i64),
      SeekFrom::End(p) => (self.limit as i64) + p,
      SeekFrom::Current(p) => (self.pos as i64) + p
    };

    if next_pos < (self.offset as i64) {
      Err(io::Error::new(ErrorKind::InvalidInput,
             "Invalid seek to a negative position"))
    } else {
      let next_pos = cmp::min(next_pos as usize, self.limit);
      self.pos = next_pos;
      Ok(self.pos() as u64)
    }
  }
}

#[test]
fn can_slice() {
  use std::io::Read;

  let v = vec![0,1,2,3];
  let b = SharedReadBuffer::new(v);

  assert_eq!(b.len(), 4);
  assert_eq!(b.remaining(), 4);
  assert_eq!(b.pos(), 0);

  let mut c = b.slice(2);
  assert_eq!(c.len(), 2);
  assert_eq!(c.remaining(), 2);

  // need some [u8] space
  let mut space = [0;2];

  assert_eq!(c.read(&mut space).unwrap(), 2);

  assert_eq!(c.len(), 2);
  assert_eq!(c.remaining(), 0);
}

#[test]
fn can_seek() {
  use std::io::Seek;

  let v = (0..10).collect();

  let mut b = SharedReadBuffer::new(v);
  assert_eq!(b.seek(SeekFrom::Start(2)).unwrap(), 2);
  assert_eq!(b.remaining(), 8);
  assert_eq!(b.len(), 10);

  // seek back to the start
  assert_eq!(b.seek(SeekFrom::Current(-2)).unwrap(), 0);
  // cant go before 0
  assert!(b.seek(SeekFrom::Current(-2)).is_err());
  assert!(b.seek(SeekFrom::End(-20)).is_err());
  assert_eq!(b.seek(SeekFrom::End(-10)).unwrap(), 0);

  assert_eq!(b.seek(SeekFrom::Start(100)).unwrap(), 10);
  assert_eq!(b.remaining(), 0);
}

#[test]
fn seek_then_slice() {
  use std::io::Seek;

  let mut b = SharedReadBuffer::new((0..10).collect());

  assert_eq!(b.seek(SeekFrom::Start(2)).unwrap(), 2);

  let c = b.slice(8);

  assert_eq!(c.remaining(), 8);
  assert_eq!(c.len(), 8);
  assert_eq!(c.pos(), 0);

  let mut c = b.slice(4);
  assert_eq!(c.remaining(), 4);
  assert_eq!(c.len(), 4);
  assert_eq!(c.pos(), 0);

  assert_eq!(c.seek(SeekFrom::Start(2)).unwrap(), 2);
  assert_eq!(c.remaining(), 2);
  assert_eq!(c.len(), 4);
  assert_eq!(c.pos(), 2);
}

#[test]
fn slice_then_seek() {
  use std::io::Seek;

  let mut b = SharedReadBuffer::new((0..10).collect());
  assert_eq!(b.seek(SeekFrom::Start(2)).unwrap(), 2);

  let mut c = b.slice(4);
  assert_eq!(c.pos(), 0);
  assert_eq!(c.len(), 4);
  assert_eq!(c.remaining(), 4);

  assert_eq!(c.seek(SeekFrom::Current(2)).unwrap(), 2);
  assert_eq!(c.pos(), 2);
  assert_eq!(c.len(), 4);
  assert_eq!(c.remaining(), 2);

}
<commit_msg>Fix bug in SharedReadBuffer<commit_after>#![crate_type = "lib"]
#![crate_name = "sharedbuffer"]

use std::sync::Arc;
use std::cmp;

use std::io;
use std::ops::Deref;
use std::io::{ErrorKind, Read, Seek, SeekFrom};

/* TODO: this would be better if we didn't indirect twice to the data
 * but that would require our own version of Arc and Vec... It shouldn't
 * be that bad but its just not important right now.
 */
#[derive(Eq,PartialEq,Clone,Debug)]
pub struct SharedReadBuffer {
  inner: Arc<Vec<u8>>,
  offset: usize, // lower limit of where we can look
  pos: usize,    // absolute position
  limit: usize   // absolute end
}

impl Deref for SharedReadBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl SharedReadBuffer {
    pub fn empty() -> SharedReadBuffer {
        SharedReadBuffer::new(Vec::new())
    }

  pub fn new(buffer: Vec<u8>) -> SharedReadBuffer {
    let lim = buffer.len();

    SharedReadBuffer {
      inner: Arc::new(buffer),
      offset: 0,
      pos: 0,
      limit: lim
    }
  }

  pub fn as_bytes(&self) -> &[u8] {
    &self.inner[self.pos..self.limit]
  }

  pub fn consume_slice(&mut self, length: usize) -> io::Result<SharedReadBuffer> {
    let next = self.slice(length);
    let _ = try!(self.seek(SeekFrom::Current(length as i64)));
    Ok(next)
  }

  pub fn consume_remaining(self) -> SharedReadBuffer {
    SharedReadBuffer {
        inner: self.inner,
        offset: self.pos,
        pos: self.pos,
        limit: self.limit
    }
  }

  pub fn slice(&self, length: usize) -> SharedReadBuffer {
    SharedReadBuffer {
      inner: self.inner.clone(),
      offset: self.pos,
      pos: self.pos,
      limit: cmp::min(self.limit, self.pos + length)
    }
  }

  pub fn len(&self) -> usize {
    self.limit - self.offset
  }

  pub fn remaining(&self) -> usize {
    self.limit - self.pos
  }

  pub fn pos(&self) -> usize {
    self.pos - self.offset
  }

  pub fn peak_reader<F,T>(&self, f: F) -> T
    where F: Fn(&mut SharedReadBuffer) -> T {
    let mut image = self.clone(); // TODO: make more efficient
    f(&mut image)
  }
}

impl io::Read for SharedReadBuffer {
  fn read(&mut self, buff: &mut [u8]) -> io::Result<usize> {
    let to_read = cmp::min(buff.len(), self.limit - self.pos);
    // copy the bytes
    unsafe {
        let ptr = self.inner.as_ptr().offset(self.pos as isize);
        std::ptr::copy(ptr, buff.as_mut_ptr(), to_read);
    }
    self.pos += to_read;

    Ok(to_read)
  }
}

impl io::Seek for SharedReadBuffer {
  fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {

    let next_pos: i64 = match pos {
      SeekFrom::Start(p) => (self.offset as i64) + (p as i64),
      SeekFrom::End(p) => (self.limit as i64) + p,
      SeekFrom::Current(p) => (self.pos as i64) + p
    };

    if next_pos < (self.offset as i64) {
      Err(io::Error::new(ErrorKind::InvalidInput,
             "Invalid seek to a negative position"))
    } else {
      let next_pos = cmp::min(next_pos as usize, self.limit);
      self.pos = next_pos;
      Ok(self.pos() as u64)
    }
  }
}

#[test]
fn read() {
  use std::io::Read;

  let v = vec![0,1,2,3];
  let mut b = SharedReadBuffer::new(v);

  let mut bts = [0;2];
  b.read(&mut bts).unwrap();

  assert_eq!(&bts, &[0,1]);

  b.read(&mut bts).unwrap();
  assert_eq!(&bts, &[2,3]);
}

#[test]
fn can_slice() {
  use std::io::Read;

  let v = vec![0,1,2,3];
  let b = SharedReadBuffer::new(v);

  assert_eq!(b.len(), 4);
  assert_eq!(b.remaining(), 4);
  assert_eq!(b.pos(), 0);

  let mut c = b.slice(2);
  assert_eq!(c.len(), 2);
  assert_eq!(c.remaining(), 2);

  // need some [u8] space
  let mut space = [0;2];

  assert_eq!(c.read(&mut space).unwrap(), 2);

  assert_eq!(c.len(), 2);
  assert_eq!(c.remaining(), 0);
}

#[test]
fn can_seek() {
  use std::io::Seek;

  let v = (0..10).collect();

  let mut b = SharedReadBuffer::new(v);
  assert_eq!(b.seek(SeekFrom::Start(2)).unwrap(), 2);
  assert_eq!(b.remaining(), 8);
  assert_eq!(b.len(), 10);

  // seek back to the start
  assert_eq!(b.seek(SeekFrom::Current(-2)).unwrap(), 0);
  // cant go before 0
  assert!(b.seek(SeekFrom::Current(-2)).is_err());
  assert!(b.seek(SeekFrom::End(-20)).is_err());
  assert_eq!(b.seek(SeekFrom::End(-10)).unwrap(), 0);

  assert_eq!(b.seek(SeekFrom::Start(100)).unwrap(), 10);
  assert_eq!(b.remaining(), 0);
}

#[test]
fn seek_then_slice() {
  use std::io::Seek;

  let mut b = SharedReadBuffer::new((0..10).collect());

  assert_eq!(b.seek(SeekFrom::Start(2)).unwrap(), 2);

  let c = b.slice(8);

  assert_eq!(c.remaining(), 8);
  assert_eq!(c.len(), 8);
  assert_eq!(c.pos(), 0);

  let mut c = b.slice(4);
  assert_eq!(c.remaining(), 4);
  assert_eq!(c.len(), 4);
  assert_eq!(c.pos(), 0);

  assert_eq!(c.seek(SeekFrom::Start(2)).unwrap(), 2);
  assert_eq!(c.remaining(), 2);
  assert_eq!(c.len(), 4);
  assert_eq!(c.pos(), 2);
}

#[test]
fn slice_then_seek() {
  use std::io::Seek;

  let mut b = SharedReadBuffer::new((0..10).collect());
  assert_eq!(b.seek(SeekFrom::Start(2)).unwrap(), 2);

  let mut c = b.slice(4);
  assert_eq!(c.pos(), 0);
  assert_eq!(c.len(), 4);
  assert_eq!(c.remaining(), 4);

  assert_eq!(c.seek(SeekFrom::Current(2)).unwrap(), 2);
  assert_eq!(c.pos(), 2);
  assert_eq!(c.len(), 4);
  assert_eq!(c.remaining(), 2);

}
<|endoftext|>


<commit_before>//! Module that contains a crawler function that crawls through the vulkan xml and returns a
//! Registry struct
use xml::reader::{Events, XmlEvent};
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;
use std::io::Read;
use std::ffi::CStr;
use {VkRegistry, VkType, VkMember};
use VkVariant;

pub fn crawl<R: Read>(xml_events: Events<R>, mut registry: VkRegistry) -> VkRegistry {
    use self::XmlElement::*;

    let mut type_buffer = VkType::Unhandled;
    let mut cur_block = VkBlock::None;
    // A variable that contains what the index of the element in vk_elements that vk_elements was
    // popped to. Used to prevent the element iterator from going over elements that have already
    // been checked.
    let mut popped_to = 0;

    // A stack of the relevant elements in the vulkan xml
    let mut vk_elements = Vec::with_capacity(10);

    for event in xml_events {

        let event = event.unwrap();
        match event {
            XmlEvent::StartElement{ name, attributes, .. } => {
                vk_elements.push(XmlElement::new_tag(name, attributes));
            }

            XmlEvent::EndElement{ name } => {
                for el in &vk_elements[popped_to..] {
                    match *el {
                        Tag{name: ref tag_name, attributes: ref tag_attrs} =>
                            match &tag_name[..] {
                                "types"      => cur_block = VkBlock::Types,
                                "enums"      => cur_block = VkBlock::Enums,
                                "commands"   => cur_block = VkBlock::Commands,
                                "extensions" => cur_block = VkBlock::Extensions,

                                "type"  =>
                                    if VkBlock::Types == cur_block {
                                        if let Some(category) = find_attribute(tag_attrs, "category") {
                                            registry.push_type(type_buffer).ok();
                                            match category {
                                                "basetype"      => type_buffer = VkType::Unhandled,
                                                "bitmask"       => type_buffer = VkType::Unhandled,
                                                "define"        => type_buffer = VkType::Unhandled,
                                                "enum"          => type_buffer = VkType::Unhandled,
                                                "funcpointer"   => type_buffer = VkType::Unhandled,
                                                "group"         => type_buffer = VkType::Unhandled,
                                                "handle"        => type_buffer = VkType::Unhandled,
                                                "include"       => type_buffer = VkType::Unhandled,
                                                "struct"        =>
                                                    type_buffer = VkType::Struct{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), fields: Vec::with_capacity(8)},
                                                "union"         =>
                                                    type_buffer = VkType::Union{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), variants: Vec::with_capacity(8)},
                                                _               => panic!("Unexpected category")
                                            }
                                        }
                                    } else {/*panic!("\"type\" tag found outside of \"types\" block")*/}, //TODO: implement fully so panic can be used

                                "member" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{ref mut fields, ..} => fields.push(VkMember::empty()),
                                            VkType::Union{ref mut variants, ..} => variants.push(VkMember::empty()),
                                            _ =>
                                                panic!("Unexpected \"member\" tag found")
                                        }
                                    } else {panic!("\"member\" tag found outside of \"types\" block")},

                                _ => ()
                            },

                        Characters{ref chars, tag} =>
                            match tag {
                                "type" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{fields: ref mut members, ..} |
                                            VkType::Union{variants: ref mut members, ..} => members.last_mut().unwrap().set_type(registry.append_str(&chars[..])),
                                            _ => ()
                                        }
                                    },
                                "member" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{fields: ref mut members, ..} |
                                            VkType::Union{variants: ref mut members, ..} =>
                                                match chars.trim() {
                                                    "const" => members.last_mut().unwrap().change_type_const(),
                                                    "*"     => members.last_mut().unwrap().change_type_ptr(),
                                                    _       => ()
                                                },
                                            _ => ()
                                        }
                                    },
                                _ => ()
                            }
                    }
                }

                pop_element_stack(&mut vk_elements);
                popped_to = vk_elements.len();
            }

            XmlEvent::Characters(chars) => {
                let tag_ptr =
                    match *vk_elements.last().unwrap() {
                        XmlElement::Tag{name: ref tag, ..} => &tag[..] as *const str,
                        // In circumstances where the xml reads something like <foo>foostart<bar>bar</bar>fooend</foo>, the
                        // "fooend" string will appear in vk_elements after the "foostart" event, instead of after <foo>.
                        // Because of that, we must pull the tag from the other Characters event.
                        XmlElement::Characters{tag, ..} => tag as *const str
                    };

                unsafe{ vk_elements.push(XmlElement::new_chars(chars, &*tag_ptr)) }
            }

            _ => ()
        }
    }

    for t in &registry.types {
        unsafe {
            match *t {
                VkType::Struct{name, ref fields} => {
                    println!("Struct {:?}", CStr::from_ptr(name));

                    for f in fields {
                        println!("type: {:?}", f.field_type);
                    }
                }
                VkType::Union{name, ref variants} => {
                    println!("Union {:?}", CStr::from_ptr(name));

                    for v in variants {
                        println!("type: {:?}", v.field_type);
                    }
                }
                _ => ()
            }
        }
    }

    registry
}

fn find_attribute<'v>(source: &'v Vec<OwnedAttribute>, query: &str) -> Option<&'v str> {
    source.into_iter().skip_while(|attr| &attr.name.local_name != query).next().map(|res| &*res.value)
}

/// Takes a mutable reference to a XmlElement stack, popping the stack of Character elements until
/// it pops a Tag
fn pop_element_stack(vk_elements: &mut Vec<XmlElement>) {
    match vk_elements.pop() {
        Some(el) =>
            if let XmlElement::Characters{..} = el {
                pop_element_stack(vk_elements)
            },

        None => panic!("Invalid xml; Unexpected closing tag")
    }
}

#[derive(Debug)]
enum XmlElement<'a> {
    Tag {
        /// The name of the tag e.g. "hello" in <hello>
        name: String,
        /// The attributes contained within the specification xml.
        attributes: Vec<OwnedAttribute>
    },
    Characters{
        chars: String,
        tag: &'a str
    }
}

impl<'a> XmlElement<'a> {
    fn new_tag(name: OwnedName, attributes: Vec<OwnedAttribute>) -> XmlElement<'a> {
        XmlElement::Tag {
            name: name.local_name,
            attributes: attributes
        }
    }

    fn new_chars(chars: String, tag: &'a str) -> XmlElement<'a> {
        XmlElement::Characters {
            chars: chars,
            tag: tag
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
enum VkBlock {
    Types,
    Enums,
    Commands,
    Extensions,
    None
}<commit_msg>Added name detection to the crawler<commit_after>//! Module that contains a crawler function that crawls through the vulkan xml and returns a
//! Registry struct
use xml::reader::{Events, XmlEvent};
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;
use std::io::Read;
use std::ffi::CStr;
use {VkRegistry, VkType, VkMember};
use VkVariant;

pub fn crawl<R: Read>(xml_events: Events<R>, mut registry: VkRegistry) -> VkRegistry {
    use self::XmlElement::*;

    let mut type_buffer = VkType::Unhandled;
    let mut cur_block = VkBlock::None;
    // A variable that contains what the index of the element in vk_elements that vk_elements was
    // popped to. Used to prevent the element iterator from going over elements that have already
    // been checked.
    let mut popped_to = 0;

    // A stack of the relevant elements in the vulkan xml
    let mut vk_elements = Vec::with_capacity(10);

    for event in xml_events {

        let event = event.unwrap();
        match event {
            XmlEvent::StartElement{ name, attributes, .. } => {
                vk_elements.push(XmlElement::new_tag(name, attributes));
            }

            XmlEvent::EndElement{ name } => {
                for el in &vk_elements[popped_to..] {
                    match *el {
                        Tag{name: ref tag_name, attributes: ref tag_attrs} =>
                            match &tag_name[..] {
                                "types"      => cur_block = VkBlock::Types,
                                "enums"      => cur_block = VkBlock::Enums,
                                "commands"   => cur_block = VkBlock::Commands,
                                "extensions" => cur_block = VkBlock::Extensions,

                                "type"  =>
                                    if VkBlock::Types == cur_block {
                                        if let Some(category) = find_attribute(tag_attrs, "category") {
                                            registry.push_type(type_buffer).ok();
                                            match category {
                                                "basetype"      => type_buffer = VkType::Unhandled,
                                                "bitmask"       => type_buffer = VkType::Unhandled,
                                                "define"        => type_buffer = VkType::Unhandled,
                                                "enum"          => type_buffer = VkType::Unhandled,
                                                "funcpointer"   => type_buffer = VkType::Unhandled,
                                                "group"         => type_buffer = VkType::Unhandled,
                                                "handle"        => type_buffer = VkType::Unhandled,
                                                "include"       => type_buffer = VkType::Unhandled,
                                                "struct"        =>
                                                    type_buffer = VkType::Struct{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), fields: Vec::with_capacity(8)},
                                                "union"         =>
                                                    type_buffer = VkType::Union{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), variants: Vec::with_capacity(8)},
                                                _               => panic!("Unexpected category")
                                            }
                                        }
                                    } else {/*panic!("\"type\" tag found outside of \"types\" block")*/}, //TODO: implement fully so panic can be used

                                "member" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{ref mut fields, ..} => fields.push(VkMember::empty()),
                                            VkType::Union{ref mut variants, ..} => variants.push(VkMember::empty()),
                                            _ =>
                                                panic!("Unexpected \"member\" tag found")
                                        }
                                    } else {panic!("\"member\" tag found outside of \"types\" block")},

                                _ => ()
                            },

                        Characters{ref chars, tag} =>
                            match tag {
                                "member" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{fields: ref mut members, ..} |
                                            VkType::Union{variants: ref mut members, ..} =>
                                                match chars.trim() {
                                                    "const" => members.last_mut().unwrap().change_type_const(),
                                                    "*"     => members.last_mut().unwrap().change_type_ptr(),
                                                    _       => ()
                                                },
                                            _ => ()
                                        }
                                    },
                                "type" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{fields: ref mut members, ..} |
                                            VkType::Union{variants: ref mut members, ..} => members.last_mut().unwrap().set_type(registry.append_str(&chars[..])),
                                            _ => ()
                                        }
                                    },
                                "name" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{fields: ref mut members, ..} |
                                            VkType::Union{variants: ref mut members, ..} => members.last_mut().unwrap().set_name(registry.append_str(&chars[..])),
                                            _ => ()
                                        }
                                    },
                                _ => ()
                            }
                    }
                }

                pop_element_stack(&mut vk_elements);
                popped_to = vk_elements.len();
            }

            XmlEvent::Characters(chars) => {
                let tag_ptr =
                    match *vk_elements.last().unwrap() {
                        XmlElement::Tag{name: ref tag, ..} => &tag[..] as *const str,
                        // In circumstances where the xml reads something like <foo>foostart<bar>bar</bar>fooend</foo>, the
                        // "fooend" string will appear in vk_elements after the "foostart" event, instead of after <foo>.
                        // Because of that, we must pull the tag from the other Characters event.
                        XmlElement::Characters{tag, ..} => tag as *const str
                    };

                unsafe{ vk_elements.push(XmlElement::new_chars(chars, &*tag_ptr)) }
            }

            _ => ()
        }
    }

    for t in &registry.types {
        unsafe {
            match *t {
                VkType::Struct{name, ref fields} => {
                    println!("Struct {:?}", CStr::from_ptr(name));

                    for f in fields {
                        println!("{:#?}", f);
                    }
                }
                VkType::Union{name, ref variants} => {
                    println!("Union {:?}", CStr::from_ptr(name));

                    for v in variants {
                        println!("{:#?}", v);
                    }
                }
                _ => ()
            }
        }
    }

    registry
}

fn find_attribute<'v>(source: &'v Vec<OwnedAttribute>, query: &str) -> Option<&'v str> {
    source.into_iter().skip_while(|attr| &attr.name.local_name != query).next().map(|res| &*res.value)
}

/// Takes a mutable reference to a XmlElement stack, popping the stack of Character elements until
/// it pops a Tag
fn pop_element_stack(vk_elements: &mut Vec<XmlElement>) {
    match vk_elements.pop() {
        Some(el) =>
            if let XmlElement::Characters{..} = el {
                pop_element_stack(vk_elements)
            },

        None => panic!("Invalid xml; Unexpected closing tag")
    }
}

#[derive(Debug)]
enum XmlElement<'a> {
    Tag {
        /// The name of the tag e.g. "hello" in <hello>
        name: String,
        /// The attributes contained within the specification xml.
        attributes: Vec<OwnedAttribute>
    },
    Characters{
        chars: String,
        tag: &'a str
    }
}

impl<'a> XmlElement<'a> {
    fn new_tag(name: OwnedName, attributes: Vec<OwnedAttribute>) -> XmlElement<'a> {
        XmlElement::Tag {
            name: name.local_name,
            attributes: attributes
        }
    }

    fn new_chars(chars: String, tag: &'a str) -> XmlElement<'a> {
        XmlElement::Characters {
            chars: chars,
            tag: tag
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
enum VkBlock {
    Types,
    Enums,
    Commands,
    Extensions,
    None
}<|endoftext|>


<commit_before>use core::util::unreachable;

pub struct Prime {
    priv vec: ~[uint],
}

impl Prime {
    pub fn new() -> Prime { Prime { vec: ~[] } }

    priv fn is_coprime(&mut self, num: uint) -> bool {
        for self.vec.each |&p| {
            if p * p > num  { return true; }
            if num % p == 0 { return false; }
        }
        return true;
    }

    priv fn grow_len(&mut self, len: uint) {
        if self.vec.len() >= len { return; }

        let mut num;
        if self.vec.is_empty() {
            self.vec.push(2);
            if self.vec.len() >= len { return; }
            num = 2;
        } else {
            num = self.vec.last().clone();
        }

        if num == 2 {
            self.vec.push(3);
            if self.vec.len() >= len { return; }
            num = 3;
        }

        while self.vec.len() < len {
            num += 2;
            if self.is_coprime(num) {
                self.vec.push(num);
            }
        }
    }

    pub fn get_at(&mut self, idx: uint) -> uint {
        self.grow_len(idx + 1);
        return self.vec[idx];
    }

    pub fn is_prime(&mut self, num: uint) -> bool {
        if num < 2 { return false; }

        for self.each |p| {
            if p * p > num  { return true;  }
            if num % p == 0 { return false; }
        }
        unreachable();
    }

    pub fn each(&mut self, f: &fn(uint) -> bool) {
        for self.each_borrow |p, _ps| {
            if !f(p) {
                return;
            }
        }
        unreachable();
    }

    pub fn each_borrow(&mut self, f: &fn(uint, &mut Prime) -> bool) {
        let init_len = self.vec.len();
        for uint::range(0, init_len) |i| {
            let p = self.vec[i];
            if !f(p, self) { return; }
        }

        let mut idx = init_len;
        loop {
            let p = self.get_at(idx);
            if !f(p, self) { return; }
            idx += 1;
        }
    }
}

priv struct Factors {
    priv num: uint,
    priv prime: &'self mut Prime
}

impl BaseIter<(uint, int)> for Factors<'self> {
    #[inline(always)]
    fn each(&self, blk: &fn(v: &(uint, int)) -> bool) {
        if self.num == 0 { return; }

        let mut itr = self.num;
        for self.prime.each |p| {
            let mut exp = 0;
            while itr % p == 0 {
                exp += 1;
                itr /= p;
            }
            // let exp = div_multi(&mut itr, p);
            if exp > 0 {
                if !blk(&(p, exp as int)) { break; }
            }
            if itr == 1 { break; }
        }
    }

    #[inline(always)]
    fn size_hint(&self) -> Option<uint> { None }
}

impl Factors<'self> {
    pub fn new(num: uint, primes: &'a mut Prime) -> Factors<'a> {
        Factors { num: num, prime: primes }
    }
}

priv fn pow(base: uint, exp: uint) -> uint {
    let mut result = 1;
    let mut itr = exp;
    let mut pow = base;
    while itr > 0 {
        if itr & 0x1 == 0x1 {
            result *= pow;
        }
        itr >>= 1;
        pow *= pow;
    }
    return result;
}

pub fn factors_to_uint<IA: BaseIter<(uint, int)>>(fs: &IA) -> uint {
    let mut result = 1;
    for fs.each() |&tp| {
        let (base, exp) = tp;
        if exp > 0 {
            result *= pow(base, exp as uint);
        } else {
            result /= pow(base, (-exp) as uint);
        }
    }
    return result;
}

pub fn num_of_divisors(num: uint, primes: &mut Prime) -> uint {
    if num == 0 { return 0; }
    let mut prod = 1;
    for Factors::new(num, primes).each |&f| {
        let (_base, exp) = f;
        prod *= (exp as uint) + 1;
    }
    return prod;
}

pub fn sum_of_divisors(num: uint, primes: &mut Prime) -> uint {
    if num == 0 { return 0; }
    let mut sum = 1;
    for Factors::new(num, primes).each |&f| {
        let (base, exp) = f;
        sum *= (pow(base, (exp as uint) + 1) - 1) / (base - 1);
    }
    return sum;
}

pub fn sum_of_proper_divisors(num: uint, primes: &mut Prime) -> uint {
    sum_of_divisors(num, primes) - num
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_prime_opidx () {
        let table  = [  2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41 ];
        let mut ps = Prime::new();

        // Generated primes
        for table.eachi() |i, p| { assert_eq!(ps.get_at(i), *p); }
        // Memoized primes
        for table.eachi() |i, p| { assert_eq!(ps.get_at(i), *p); }
    }

    #[test]
    fn test_prime_each() {
        let table  = ~[  2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41 ];
        let table2 = ~[ 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 ];
        let mut ps = Prime::new();

        let mut v1 = ~[];
        for ps.each |p| {
            if p > *table.last() { break; }
            v1 += [ p ];
        }
        assert_eq!(table.initn(0), v1.initn(0));

        let mut v2 = ~[];
        for ps.each |p| {
            if p > *table.last() { break; }
            v2 += [ p ];
        }
        assert_eq!(table.initn(0), v2.initn(0));

        let mut v3 = ~[];
        for ps.each |p| {
            if p > *table2.last() { break; }
            v3 += [ p ];
        }
        assert_eq!(table + table2, v3);
    }

    #[test]
    fn test_prime_is_prime() {
        let mut p = Prime::new();
        assert!(!p.is_prime(0));
        assert!(!p.is_prime(1));
        assert!(p.is_prime(2));
        assert!(p.is_prime(3));
        assert!(!p.is_prime(4));
        assert!(p.is_prime(5));
        assert!(!p.is_prime(6));
        assert!(p.is_prime(7));
        assert!(!p.is_prime(100));
    }

    #[test]
    fn test_factors() {
        let mut p = Prime::new();
        for Factors::new(1, &mut p).each |_f| {
            fail!();
        }

        for Factors::new(8, &mut p).each |&f| {
            assert_eq!(f, (2, 3));
        }

        let mut v = ~[(2, 3), (3, 3)];
        for Factors::new(8 * 27, &mut p).each |&f| {
            assert_eq!(f, v.shift());
        }
    }
}
<commit_msg>Inlining prime<commit_after>use core::util::unreachable;

pub struct Prime {
    priv vec: ~[uint],
}

impl Prime {
    #[inline(always)]
    pub fn new() -> Prime { Prime { vec: ~[] } }

    #[inline(always)]
    priv fn is_coprime(&mut self, num: uint) -> bool {
        for self.vec.each |&p| {
            if p * p > num  { return true; }
            if num % p == 0 { return false; }
        }
        return true;
    }

    #[inline(always)]
    priv fn grow_len(&mut self, len: uint) {
        if self.vec.len() >= len { return; }

        let mut num;
        if self.vec.is_empty() {
            self.vec.push(2);
            if self.vec.len() >= len { return; }
            num = 2;
        } else {
            num = self.vec.last().clone();
        }

        if num == 2 {
            self.vec.push(3);
            if self.vec.len() >= len { return; }
            num = 3;
        }

        while self.vec.len() < len {
            num += 2;
            if self.is_coprime(num) {
                self.vec.push(num);
            }
        }
    }

    #[inline(always)]
    pub fn get_at(&mut self, idx: uint) -> uint {
        self.grow_len(idx + 1);
        return self.vec[idx];
    }

    #[inline(always)]
    pub fn is_prime(&mut self, num: uint) -> bool {
        if num < 2 { return false; }

        for self.each |p| {
            if p * p > num  { return true;  }
            if num % p == 0 { return false; }
        }
        unreachable();
    }

    #[inline(always)]
    pub fn each(&mut self, f: &fn(uint) -> bool) {
        for self.each_borrow |p, _ps| {
            if !f(p) {
                return;
            }
        }
        unreachable();
    }

    #[inline(always)]
    pub fn each_borrow(&mut self, f: &fn(uint, &mut Prime) -> bool) {
        let init_len = self.vec.len();
        for uint::range(0, init_len) |i| {
            let p = self.vec[i];
            if !f(p, self) { return; }
        }

        let mut idx = init_len;
        loop {
            let p = self.get_at(idx);
            if !f(p, self) { return; }
            idx += 1;
        }
    }
}

priv struct Factors {
    priv num: uint,
    priv prime: &'self mut Prime
}

impl BaseIter<(uint, int)> for Factors<'self> {
    #[inline(always)]
    fn each(&self, blk: &fn(v: &(uint, int)) -> bool) {
        if self.num == 0 { return; }

        let mut itr = self.num;
        for self.prime.each |p| {
            let mut exp = 0;
            while itr % p == 0 {
                exp += 1;
                itr /= p;
            }
            // let exp = div_multi(&mut itr, p);
            if exp > 0 {
                if !blk(&(p, exp as int)) { break; }
            }
            if itr == 1 { break; }
        }
    }

    #[inline(always)]
    fn size_hint(&self) -> Option<uint> { None }
}

impl Factors<'self> {
    #[inline(always)]
    pub fn new(num: uint, primes: &'a mut Prime) -> Factors<'a> {
        Factors { num: num, prime: primes }
    }
}

#[inline(always)]
priv fn pow(base: uint, exp: uint) -> uint {
    let mut result = 1;
    let mut itr = exp;
    let mut pow = base;
    while itr > 0 {
        if itr & 0x1 == 0x1 {
            result *= pow;
        }
        itr >>= 1;
        pow *= pow;
    }
    return result;
}

#[inline(always)]
pub fn factors_to_uint<IA: BaseIter<(uint, int)>>(fs: &IA) -> uint {
    let mut result = 1;
    for fs.each() |&tp| {
        let (base, exp) = tp;
        if exp > 0 {
            result *= pow(base, exp as uint);
        } else {
            result /= pow(base, (-exp) as uint);
        }
    }
    return result;
}

#[inline(always)]
pub fn num_of_divisors(num: uint, primes: &mut Prime) -> uint {
    if num == 0 { return 0; }
    let mut prod = 1;
    for Factors::new(num, primes).each |&f| {
        let (_base, exp) = f;
        prod *= (exp as uint) + 1;
    }
    return prod;
}

#[inline(always)]
pub fn sum_of_divisors(num: uint, primes: &mut Prime) -> uint {
    if num == 0 { return 0; }
    let mut sum = 1;
    for Factors::new(num, primes).each |&f| {
        let (base, exp) = f;
        sum *= (pow(base, (exp as uint) + 1) - 1) / (base - 1);
    }
    return sum;
}

pub fn sum_of_proper_divisors(num: uint, primes: &mut Prime) -> uint {
    sum_of_divisors(num, primes) - num
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_prime_opidx () {
        let table  = [  2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41 ];
        let mut ps = Prime::new();

        // Generated primes
        for table.eachi() |i, p| { assert_eq!(ps.get_at(i), *p); }
        // Memoized primes
        for table.eachi() |i, p| { assert_eq!(ps.get_at(i), *p); }
    }

    #[test]
    fn test_prime_each() {
        let table  = ~[  2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41 ];
        let table2 = ~[ 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 ];
        let mut ps = Prime::new();

        let mut v1 = ~[];
        for ps.each |p| {
            if p > *table.last() { break; }
            v1 += [ p ];
        }
        assert_eq!(table.initn(0), v1.initn(0));

        let mut v2 = ~[];
        for ps.each |p| {
            if p > *table.last() { break; }
            v2 += [ p ];
        }
        assert_eq!(table.initn(0), v2.initn(0));

        let mut v3 = ~[];
        for ps.each |p| {
            if p > *table2.last() { break; }
            v3 += [ p ];
        }
        assert_eq!(table + table2, v3);
    }

    #[test]
    fn test_prime_is_prime() {
        let mut p = Prime::new();
        assert!(!p.is_prime(0));
        assert!(!p.is_prime(1));
        assert!(p.is_prime(2));
        assert!(p.is_prime(3));
        assert!(!p.is_prime(4));
        assert!(p.is_prime(5));
        assert!(!p.is_prime(6));
        assert!(p.is_prime(7));
        assert!(!p.is_prime(100));
    }

    #[test]
    fn test_factors() {
        let mut p = Prime::new();
        for Factors::new(1, &mut p).each |_f| {
            fail!();
        }

        for Factors::new(8, &mut p).each |&f| {
            assert_eq!(f, (2, 3));
        }

        let mut v = ~[(2, 3), (3, 3)];
        for Factors::new(8 * 27, &mut p).each |&f| {
            assert_eq!(f, v.shift());
        }
    }
}
<|endoftext|>


<commit_before>use clap::App;
use std::default::Default;
use thud_game;
use thud_ui_common;
use thud_ui_console;

fn main() {
  let mut agents = thud_ui_common::agent_registry::AgentRegistry::new();
  agents
    .register(Box::new(
      thud_ui_common::agent_registry::StdinAgentBuilder::new(),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::mcts::MctsAgentBuilder::new("mcts"),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::FileAgentBuilder::new("file_agent"),
    ));

  // Set up arg handling.
  let matches = {
    let mut app = thud_ui_common::set_args(
      App::new("console_play")
        .version("0.1.0")
        .author("Stu Black <trurl@freeshell.org>")
        .about("Play Thud on the console"),
      &[
        thud_ui_common::FLAG_INITIAL_BOARD,
        thud_ui_common::FLAG_INITIAL_PLAYER,
        thud_ui_common::FLAG_LOG_LEVEL,
      ],
    );
    app = agents.register_args(app);
    app.get_matches()
  };
  let initial_cells = match matches
    .value_of(thud_ui_common::FLAG_INITIAL_BOARD)
    .map(|x| x.parse::<thud_ui_common::InitialBoard>())
  {
    None => thud_game::board::Cells::default(),
    Some(Ok(x)) => x.cells(),
    Some(Err(e)) => panic!("Bad initial board configuration: {}", e),
  };
  let logging_level = match matches
    .value_of(thud_ui_common::FLAG_LOG_LEVEL)
    .map(|x| x.parse::<log::LevelFilter>())
  {
    Some(Ok(x)) => x,
    Some(Err(_)) => panic!(
      "Bad logging level '{}'",
      matches.value_of(thud_ui_common::FLAG_LOG_LEVEL).unwrap()
    ),
    None => log::LevelFilter::Info,
  };

  // Set up logging.
  thud_ui_common::init::init_logger(logging_level);

  let mut agent1 = agents.get_player_1_from_arguments(&matches).unwrap();
  let mut agent2 = agents.get_player_2_from_arguments(&matches).unwrap();
  let mut state = thud_game::state::State::new(
    initial_cells,
    &thud_game::board::TRANSPOSITIONAL_EQUIVALENCE,
  );
  while !state.terminated() {
    println!("state: {:?}", state);
    let action = agent1.propose_action(&state).unwrap();
    println!("agent 1 proposes action: {:?}", action);
    state.do_action(&action);
    println!("state: {:?}", state);
    if state.terminated() {
      break;
    }
    let action = agent2.propose_action(&state).unwrap();
    println!("agent 2 proposes action: {:?}", action);
    state.do_action(&action);
  }
  println!("state has terminated");

  // // Prompt for play.
  // loop {
  //   println!(
  //     "{:?} player's turn. Enter coordinate of piece to move.",
  //     human_role
  //   );
  //   let c = thud_ui_console::prompt_for_piece(state.cells(), human_role);
  //   let piece_actions: Vec<thud_game::Action> = state.position_actions(c).collect();
  //   if piece_actions.is_empty() {
  //     println!("Piece at {:?} has no actions.", c);
  //   } else {
  //     if let Some(action) = thud_ui_console::select_one(&piece_actions) {
  //       let mut moved_state = state.clone();
  //       moved_state.do_action(&action);
  //       println!(
  //         "After action, board: {}",
  //         thud_game::board::format_board(moved_state.cells())
  //       );
  //       println!("Is this okay?");
  //       match thud_ui_console::select_one(&["y", "n"]) {
  //         Some(&"y") => {
  //           state = moved_state;
  //           graph.retain_reachable_from(&[&state]);
  //           break;
  //         }
  //         _ => continue,
  //       }
  //     }
  //   }
  // }
}
<commit_msg>Add another potential MCTS agent to console_play to enable self-play.<commit_after>use clap::App;
use std::default::Default;
use thud_game;
use thud_ui_common;
use thud_ui_console;

fn main() {
  let mut agents = thud_ui_common::agent_registry::AgentRegistry::new();
  agents
    .register(Box::new(
      thud_ui_common::agent_registry::StdinAgentBuilder::new(),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::mcts::MctsAgentBuilder::new("mcts1"),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::mcts::MctsAgentBuilder::new("mcts2"),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::FileAgentBuilder::new("file_agent"),
    ));

  // Set up arg handling.
  let matches = {
    let mut app = thud_ui_common::set_args(
      App::new("console_play")
        .version("0.1.0")
        .author("Stu Black <trurl@freeshell.org>")
        .about("Play Thud on the console"),
      &[
        thud_ui_common::FLAG_INITIAL_BOARD,
        thud_ui_common::FLAG_INITIAL_PLAYER,
        thud_ui_common::FLAG_LOG_LEVEL,
      ],
    );
    app = agents.register_args(app);
    app.get_matches()
  };
  let initial_cells = match matches
    .value_of(thud_ui_common::FLAG_INITIAL_BOARD)
    .map(|x| x.parse::<thud_ui_common::InitialBoard>())
  {
    None => thud_game::board::Cells::default(),
    Some(Ok(x)) => x.cells(),
    Some(Err(e)) => panic!("Bad initial board configuration: {}", e),
  };
  let logging_level = match matches
    .value_of(thud_ui_common::FLAG_LOG_LEVEL)
    .map(|x| x.parse::<log::LevelFilter>())
  {
    Some(Ok(x)) => x,
    Some(Err(_)) => panic!(
      "Bad logging level '{}'",
      matches.value_of(thud_ui_common::FLAG_LOG_LEVEL).unwrap()
    ),
    None => log::LevelFilter::Info,
  };

  // Set up logging.
  thud_ui_common::init::init_logger(logging_level);

  let mut agent1 = agents.get_player_1_from_arguments(&matches).unwrap();
  let mut agent2 = agents.get_player_2_from_arguments(&matches).unwrap();
  let mut state = thud_game::state::State::new(
    initial_cells,
    &thud_game::board::TRANSPOSITIONAL_EQUIVALENCE,
  );
  while !state.terminated() {
    println!("state: {:?}", state);
    let action = agent1.propose_action(&state).unwrap();
    println!("agent 1 proposes action: {:?}", action);
    state.do_action(&action);
    println!("state: {:?}", state);
    if state.terminated() {
      break;
    }
    let action = agent2.propose_action(&state).unwrap();
    println!("agent 2 proposes action: {:?}", action);
    state.do_action(&action);
  }
  println!("state has terminated: {:?}", state);

  // // Prompt for play.
  // loop {
  //   println!(
  //     "{:?} player's turn. Enter coordinate of piece to move.",
  //     human_role
  //   );
  //   let c = thud_ui_console::prompt_for_piece(state.cells(), human_role);
  //   let piece_actions: Vec<thud_game::Action> = state.position_actions(c).collect();
  //   if piece_actions.is_empty() {
  //     println!("Piece at {:?} has no actions.", c);
  //   } else {
  //     if let Some(action) = thud_ui_console::select_one(&piece_actions) {
  //       let mut moved_state = state.clone();
  //       moved_state.do_action(&action);
  //       println!(
  //         "After action, board: {}",
  //         thud_game::board::format_board(moved_state.cells())
  //       );
  //       println!("Is this okay?");
  //       match thud_ui_console::select_one(&["y", "n"]) {
  //         Some(&"y") => {
  //           state = moved_state;
  //           graph.retain_reachable_from(&[&state]);
  //           break;
  //         }
  //         _ => continue,
  //       }
  //     }
  //   }
  // }
}
<|endoftext|>


<commit_before>extern crate diff;
extern crate lalrpop_util;

use std::cell::RefCell;

use lalrpop_util::{ErrorRecovery, ParseError};

use util::tok::Tok;

/// demonstration from the Greene text; one of the simplest grammars
/// that still ensures we get parse tree correct
mod sub;

/// test something other than test-all
mod sub_ascent;
mod sub_table;

/// more interesting demonstration of parsing full expressions
mod expr;

/// more interesting demonstration of parsing full expressions, using LALR not LR
mod expr_lalr;

/// more interesting demonstration of parsing full expressions, using intern tok
mod expr_intern_tok;

/// test that passes in lifetime/type/formal parameters and threads
/// them through, building an AST from the result
mod expr_arena;

/// definitions of the AST
mod expr_arena_ast;

/// expr defined with a generic type `F`
mod expr_generic;

mod generics_issue_104;
mod generics_issue_104_lib;

/// test of inlining
mod inline;

/// test that exercises internal token generation, as well as locations and spans
mod intern_tok;

/// test that exercises using a lifetime parameter in the token type
mod lifetime_tok;

/// library for lifetime_tok test
mod lifetime_tok_lib;

/// test that exercises locations and spans
mod loc;

/// regression test for location issue #90
mod loc_issue_90;
mod loc_issue_90_lib;

/// test that uses `super` in paths in various places
mod use_super;

/// test that exercises locations and spans
mod error;

/// Test error recovery
mod error_recovery;
mod error_recovery_pull_182;

/// test for inlining expansion issue #55
mod issue_55;

/// test for unit action code
mod unit;

/// test for match section
mod match_section;

// Check that error recovery (which requires cloneable tokens) is not created if it is not used
#[allow(unused)]
mod no_clone_tok;

mod util;

/// This constant is here so that some of the generator parsers can
/// refer to it in order to test `super::` handling in action code.
const ZERO: i32 = 0;

#[test]
fn expr_test1() {
    util::test(|v| expr::parse_Expr(1, v), "22 - 3", 22 - 3);
}

#[test]
fn expr_test2() {
    util::test(|v| expr::parse_Expr(1, v), "22 - (3 + 5)", 22 - (3 + 5));
}

#[test]
fn expr_test3() {
    util::test(|v| expr::parse_Expr(1, v), "22 - (3 - 5) - 13", 22 - (3 - 5) - 13);
}

#[test]
fn expr_test4() {
    util::test(|v| expr::parse_Expr(1, v), "22 * 3 - 6", 22 * 3 - 6);
}

#[test]
fn expr_test5() {
    util::test(|v| expr::parse_Expr(11, v), "22 * 3 - 6", 22*11 * 3*11 - 6*11);
}

#[test]
fn expr_intern_tok_test1() {
    assert_eq!(expr_intern_tok::parse_Expr(1, "22 - 3").unwrap(), 22 - 3);
}

#[test]
fn expr_intern_tok_test2() {
    assert_eq!(expr_intern_tok::parse_Expr(1, "22 - (3 - 5) - 13").unwrap(), 22 - (3 - 5) - 13);
}

#[test]
fn expr_intern_tok_test_err() {
    match expr_intern_tok::parse_Expr(1, "22 - (3 - 5) - X") {
        //                                0123456789012345
        Err(ParseError::InvalidToken { location }) => {
            assert_eq!(location, 15);
        }
        r => {
            panic!("invalid result {:?}", r);
        }
    }
}

#[test]
fn expr_lifetime_tok1() {
    // the problem here was that we were improperly pruning the 'input from the
    let tokens = lifetime_tok_lib::lt_tokenize("x");
    let tree = lifetime_tok::parse_Expr(tokens).unwrap();
    assert_eq!(tree, vec!["x"]);
}

#[test]
fn expr_lalr_test1() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 - 3", 22 - 3);
}

#[test]
fn expr_lalr_test2() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 - (3 + 5)", 22 - (3 + 5));
}

#[test]
fn expr_lalr_test3() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 - (3 - 5) - 13", 22 - (3 - 5) - 13);
}

#[test]
fn expr_lalr_test4() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 * 3 - 6", 22 * 3 - 6);
}

#[test]
fn expr_lalr_test5() {
    util::test(|v| expr_lalr::parse_Expr(11, v), "22 * 3 - 6", 22*11 * 3*11 - 6*11);
}

#[test]
fn inline_test1() {
    assert_eq!(inline::parse_E("& L L").unwrap(), "& L L");
}

#[test]
fn sub_test1() {
    util::test(sub::parse_S, "22 - 3", 22 - 3);
}

#[test]
fn sub_test2() {
    util::test(sub::parse_S, "22 - (3 - 5)", 22 - (3 - 5));
}

#[test]
fn sub_test3() {
    util::test(sub::parse_S, "22 - (3 - 5) - 13", 22 - (3 - 5) - 13);
}

#[test]
fn sub_ascent_test1() {
    util::test(sub_ascent::parse_S, "22 - 3", 22 - 3);
}

#[test]
fn sub_table_test1() {
    util::test(sub_table::parse_S, "22 - 3", 22 - 3);
}

#[test]
fn expr_arena_test1() {
    use expr_arena_ast::*;
    let arena = Arena::new();
    let expected =
        arena.alloc(Node::Binary(Op::Sub,
                                 arena.alloc(Node::Binary(Op::Mul,
                                                          arena.alloc(Node::Value(22)),
                                                          arena.alloc(Node::Value(3)))),
                                 arena.alloc(Node::Value(6))));
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "22 * 3 - 6", expected);
}

#[test]
fn expr_arena_test2() {
    use expr_arena_ast::*;
    let arena = Arena::new();
    let expected =
        arena.alloc(Node::Reduce(Op::Mul,
                                 vec![arena.alloc(Node::Value(22)),
                                      arena.alloc(Node::Value(3)),
                                      arena.alloc(Node::Value(6))]));;
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "*(22, 3, 6)", expected);
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "*(22, 3, 6,)", expected);
}

#[test]
fn expr_arena_test3() {
    use expr_arena_ast::*;
    let arena = Arena::new();
    let expected =
        arena.alloc(
            Node::Binary(Op::Mul,
                         arena.alloc(Node::Value(22)),
                         arena.alloc(Node::Paren(
                             arena.alloc(
                                 Node::Binary(Op::Sub,
                                              arena.alloc(Node::Value(3)),
                                              arena.alloc(Node::Value(6))))))));
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "22 * (3 - 6)", expected);
}

#[test]
fn expr_generic_test1() {
    let expected: i32 = 22 * 3 - 6;
    let actual = expr_generic::parse_Expr::<i32>("22 * 3 - 6").unwrap();
    assert_eq!(expected, actual);
}

#[test]
fn intern_tok_test1() {
    let expected = vec![(0, 0), // spans of `+` characters, measured in bytes
                        (2, 3),
                        (4, 5),
                        (8, 9)];
    let actual = intern_tok::parse_Items("--+-+---+").unwrap();
    //                                    012345678
    assert_eq!(actual, expected);
}

#[test]
fn loc_test1() {
    let expected = vec![(0, 0), // note that tok.rs generates odd spans, measured in 2*chars
                        (4, 5),
                        (8, 9),
                        (16, 17)];
    util::test_loc(|v| loc::parse_Items(v), "--+-+---+", expected);
    //                                       000001111
    //                                       024680246
}

#[test]
fn loc_test2() {
    util::test_loc(|v| loc::parse_Items(v), "+", vec![(0, 0),
                                                      (0, 1)]);
}

#[test]
fn loc_empty() {
    // test what happens when `@L` and `@R` are invoked on an empty input
    util::test_loc(|v| loc::parse_Items(v), "", vec![(0, 0)]);
}

#[test]
fn use_super_test1() {
    util::test(|v| use_super::parse_S(v), "()", 0);
}

#[test]
fn error_test1() {
    match util::test_err_gen(error::parse_Items, "---+") {
        Err(ParseError::User { error: '+' }) => { /* OK! */ }
        r => {
            panic!("unexpected response from parser: {:?}", r);
        }
    }
}

#[test]
fn error_recovery_eof() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "--", '!'.to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: None,
            expected: vec!["\"-\"".to_string()],
        },
        dropped_tokens: vec![],
    });
}

#[test]
fn error_recovery_eof_without_recovery() {
    let errors = RefCell::new(vec![]);
    let tokens = util::tok::tokenize("-").into_iter().map(|t| t.1);
    let result = error_recovery::parse_Item(&errors, tokens);
    assert_eq!(result, Err(ParseError::UnrecognizedToken {
        token: None,
        expected: vec!["\"-\"".to_string()],
    }));
}

#[test]
fn error_recovery_extra_token() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "(++)", "()".to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: Some(((), Tok::Plus,())),
            expected: vec!["\")\"".to_string()],
        },
        dropped_tokens: vec![((), Tok::Plus, ())],
    });
}

#[test]
fn error_recovery_dont_drop_unrecognized_token() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "(--)", "(!)".to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: Some(((), Tok::RParen,())),
            expected: vec!["\"-\"".to_string()],
        },
        dropped_tokens: vec![],
    });
}

#[test]
fn error_recovery_multiple_extra_tokens() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "(+++)", "()".to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: Some(((), Tok::Plus,())),
            expected: vec!["\")\"".to_string()],
        },
        dropped_tokens: vec![((), Tok::Plus, ()), ((), Tok::Plus, ())],
    });
}

#[test]
fn error_recovery_dont_panic_on_reduce_normal() {
    let mut errors = vec![];
    util::test(|v| error_recovery_pull_182::parse_Item(&mut errors, v), "1+/", ());

    assert_eq!(errors.len(), 1);
}

#[test]
fn error_recovery_dont_panic_on_reduce_at_eof() {
    let mut errors = vec![];
    util::test(|v| error_recovery_pull_182::parse_Item(&mut errors, v), "1+", ());

    assert_eq!(errors.len(), 1);
}

#[test]
fn issue_55_test1() {
    // Issue 55 caused us to either accept NO assoc types or assoc
    // types both before and after, so check that we can parse with
    // assoc types on either side.

    let (a, b, c) = issue_55::parse_E("{ type X; type Y; enum Z { } }").unwrap();
    assert_eq!(a, vec!["X", "Y"]);
    assert_eq!(b, "Z");
    assert!(c.is_empty());

    let (a, b, c) = issue_55::parse_E("{ enum Z { } type X; type Y; }").unwrap();
    assert!(a.is_empty());
    assert_eq!(b, "Z");
    assert_eq!(c, vec!["X", "Y"]);
}

#[test]
fn unit_test1() {
    assert!(unit::parse_Expr("3 + 4 * 5").is_ok());
}

#[test]
fn unit_test2() {
    assert!(unit::parse_Expr("3 + +").is_err());
}

#[test]
fn generics_issue_104_test1() {
    // The real thing `generics_issue_104` is testing is that the code
    // *compiles*, even though the type parameter `T` does not appear
    // in any of the arguments.
    assert!(generics_issue_104::parse_Schema::<()>("grammar { foo }").is_ok());
}

#[test]
fn match_section() {
    assert!(match_section::parse_Query("SELECT foo").is_ok());
    assert!(match_section::parse_Query("select foo").is_ok());
    assert!(match_section::parse_Query("INSERT foo").is_ok());
    assert!(match_section::parse_Query("UPDATE foo").is_ok());
    assert!(match_section::parse_Query("UPDATE update").is_err());
}
<commit_msg>rename test to avoid shadowing module name<commit_after>extern crate diff;
extern crate lalrpop_util;

use std::cell::RefCell;

use lalrpop_util::{ErrorRecovery, ParseError};

use util::tok::Tok;

/// demonstration from the Greene text; one of the simplest grammars
/// that still ensures we get parse tree correct
mod sub;

/// test something other than test-all
mod sub_ascent;
mod sub_table;

/// more interesting demonstration of parsing full expressions
mod expr;

/// more interesting demonstration of parsing full expressions, using LALR not LR
mod expr_lalr;

/// more interesting demonstration of parsing full expressions, using intern tok
mod expr_intern_tok;

/// test that passes in lifetime/type/formal parameters and threads
/// them through, building an AST from the result
mod expr_arena;

/// definitions of the AST
mod expr_arena_ast;

/// expr defined with a generic type `F`
mod expr_generic;

mod generics_issue_104;
mod generics_issue_104_lib;

/// test of inlining
mod inline;

/// test that exercises internal token generation, as well as locations and spans
mod intern_tok;

/// test that exercises using a lifetime parameter in the token type
mod lifetime_tok;

/// library for lifetime_tok test
mod lifetime_tok_lib;

/// test that exercises locations and spans
mod loc;

/// regression test for location issue #90
mod loc_issue_90;
mod loc_issue_90_lib;

/// test that uses `super` in paths in various places
mod use_super;

/// test that exercises locations and spans
mod error;

/// Test error recovery
mod error_recovery;
mod error_recovery_pull_182;

/// test for inlining expansion issue #55
mod issue_55;

/// test for unit action code
mod unit;

/// test for match section
mod match_section;

// Check that error recovery (which requires cloneable tokens) is not created if it is not used
#[allow(unused)]
mod no_clone_tok;

mod util;

/// This constant is here so that some of the generator parsers can
/// refer to it in order to test `super::` handling in action code.
const ZERO: i32 = 0;

#[test]
fn expr_test1() {
    util::test(|v| expr::parse_Expr(1, v), "22 - 3", 22 - 3);
}

#[test]
fn expr_test2() {
    util::test(|v| expr::parse_Expr(1, v), "22 - (3 + 5)", 22 - (3 + 5));
}

#[test]
fn expr_test3() {
    util::test(|v| expr::parse_Expr(1, v), "22 - (3 - 5) - 13", 22 - (3 - 5) - 13);
}

#[test]
fn expr_test4() {
    util::test(|v| expr::parse_Expr(1, v), "22 * 3 - 6", 22 * 3 - 6);
}

#[test]
fn expr_test5() {
    util::test(|v| expr::parse_Expr(11, v), "22 * 3 - 6", 22*11 * 3*11 - 6*11);
}

#[test]
fn expr_intern_tok_test1() {
    assert_eq!(expr_intern_tok::parse_Expr(1, "22 - 3").unwrap(), 22 - 3);
}

#[test]
fn expr_intern_tok_test2() {
    assert_eq!(expr_intern_tok::parse_Expr(1, "22 - (3 - 5) - 13").unwrap(), 22 - (3 - 5) - 13);
}

#[test]
fn expr_intern_tok_test_err() {
    match expr_intern_tok::parse_Expr(1, "22 - (3 - 5) - X") {
        //                                0123456789012345
        Err(ParseError::InvalidToken { location }) => {
            assert_eq!(location, 15);
        }
        r => {
            panic!("invalid result {:?}", r);
        }
    }
}

#[test]
fn expr_lifetime_tok1() {
    // the problem here was that we were improperly pruning the 'input from the
    let tokens = lifetime_tok_lib::lt_tokenize("x");
    let tree = lifetime_tok::parse_Expr(tokens).unwrap();
    assert_eq!(tree, vec!["x"]);
}

#[test]
fn expr_lalr_test1() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 - 3", 22 - 3);
}

#[test]
fn expr_lalr_test2() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 - (3 + 5)", 22 - (3 + 5));
}

#[test]
fn expr_lalr_test3() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 - (3 - 5) - 13", 22 - (3 - 5) - 13);
}

#[test]
fn expr_lalr_test4() {
    util::test(|v| expr_lalr::parse_Expr(1, v), "22 * 3 - 6", 22 * 3 - 6);
}

#[test]
fn expr_lalr_test5() {
    util::test(|v| expr_lalr::parse_Expr(11, v), "22 * 3 - 6", 22*11 * 3*11 - 6*11);
}

#[test]
fn inline_test1() {
    assert_eq!(inline::parse_E("& L L").unwrap(), "& L L");
}

#[test]
fn sub_test1() {
    util::test(sub::parse_S, "22 - 3", 22 - 3);
}

#[test]
fn sub_test2() {
    util::test(sub::parse_S, "22 - (3 - 5)", 22 - (3 - 5));
}

#[test]
fn sub_test3() {
    util::test(sub::parse_S, "22 - (3 - 5) - 13", 22 - (3 - 5) - 13);
}

#[test]
fn sub_ascent_test1() {
    util::test(sub_ascent::parse_S, "22 - 3", 22 - 3);
}

#[test]
fn sub_table_test1() {
    util::test(sub_table::parse_S, "22 - 3", 22 - 3);
}

#[test]
fn expr_arena_test1() {
    use expr_arena_ast::*;
    let arena = Arena::new();
    let expected =
        arena.alloc(Node::Binary(Op::Sub,
                                 arena.alloc(Node::Binary(Op::Mul,
                                                          arena.alloc(Node::Value(22)),
                                                          arena.alloc(Node::Value(3)))),
                                 arena.alloc(Node::Value(6))));
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "22 * 3 - 6", expected);
}

#[test]
fn expr_arena_test2() {
    use expr_arena_ast::*;
    let arena = Arena::new();
    let expected =
        arena.alloc(Node::Reduce(Op::Mul,
                                 vec![arena.alloc(Node::Value(22)),
                                      arena.alloc(Node::Value(3)),
                                      arena.alloc(Node::Value(6))]));;
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "*(22, 3, 6)", expected);
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "*(22, 3, 6,)", expected);
}

#[test]
fn expr_arena_test3() {
    use expr_arena_ast::*;
    let arena = Arena::new();
    let expected =
        arena.alloc(
            Node::Binary(Op::Mul,
                         arena.alloc(Node::Value(22)),
                         arena.alloc(Node::Paren(
                             arena.alloc(
                                 Node::Binary(Op::Sub,
                                              arena.alloc(Node::Value(3)),
                                              arena.alloc(Node::Value(6))))))));
    util::test_loc(|v| expr_arena::parse_Expr(&arena, v), "22 * (3 - 6)", expected);
}

#[test]
fn expr_generic_test1() {
    let expected: i32 = 22 * 3 - 6;
    let actual = expr_generic::parse_Expr::<i32>("22 * 3 - 6").unwrap();
    assert_eq!(expected, actual);
}

#[test]
fn intern_tok_test1() {
    let expected = vec![(0, 0), // spans of `+` characters, measured in bytes
                        (2, 3),
                        (4, 5),
                        (8, 9)];
    let actual = intern_tok::parse_Items("--+-+---+").unwrap();
    //                                    012345678
    assert_eq!(actual, expected);
}

#[test]
fn loc_test1() {
    let expected = vec![(0, 0), // note that tok.rs generates odd spans, measured in 2*chars
                        (4, 5),
                        (8, 9),
                        (16, 17)];
    util::test_loc(|v| loc::parse_Items(v), "--+-+---+", expected);
    //                                       000001111
    //                                       024680246
}

#[test]
fn loc_test2() {
    util::test_loc(|v| loc::parse_Items(v), "+", vec![(0, 0),
                                                      (0, 1)]);
}

#[test]
fn loc_empty() {
    // test what happens when `@L` and `@R` are invoked on an empty input
    util::test_loc(|v| loc::parse_Items(v), "", vec![(0, 0)]);
}

#[test]
fn use_super_test1() {
    util::test(|v| use_super::parse_S(v), "()", 0);
}

#[test]
fn error_test1() {
    match util::test_err_gen(error::parse_Items, "---+") {
        Err(ParseError::User { error: '+' }) => { /* OK! */ }
        r => {
            panic!("unexpected response from parser: {:?}", r);
        }
    }
}

#[test]
fn error_recovery_eof() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "--", '!'.to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: None,
            expected: vec!["\"-\"".to_string()],
        },
        dropped_tokens: vec![],
    });
}

#[test]
fn error_recovery_eof_without_recovery() {
    let errors = RefCell::new(vec![]);
    let tokens = util::tok::tokenize("-").into_iter().map(|t| t.1);
    let result = error_recovery::parse_Item(&errors, tokens);
    assert_eq!(result, Err(ParseError::UnrecognizedToken {
        token: None,
        expected: vec!["\"-\"".to_string()],
    }));
}

#[test]
fn error_recovery_extra_token() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "(++)", "()".to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: Some(((), Tok::Plus,())),
            expected: vec!["\")\"".to_string()],
        },
        dropped_tokens: vec![((), Tok::Plus, ())],
    });
}

#[test]
fn error_recovery_dont_drop_unrecognized_token() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "(--)", "(!)".to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: Some(((), Tok::RParen,())),
            expected: vec!["\"-\"".to_string()],
        },
        dropped_tokens: vec![],
    });
}

#[test]
fn error_recovery_multiple_extra_tokens() {
    let errors = RefCell::new(vec![]);
    util::test(|v| error_recovery::parse_Item(&errors, v), "(+++)", "()".to_string());

    assert_eq!(errors.borrow().len(), 1);
    assert_eq!(errors.borrow()[0], ErrorRecovery {
        error: ParseError::UnrecognizedToken {
            token: Some(((), Tok::Plus,())),
            expected: vec!["\")\"".to_string()],
        },
        dropped_tokens: vec![((), Tok::Plus, ()), ((), Tok::Plus, ())],
    });
}

#[test]
fn error_recovery_dont_panic_on_reduce_normal() {
    let mut errors = vec![];
    util::test(|v| error_recovery_pull_182::parse_Item(&mut errors, v), "1+/", ());

    assert_eq!(errors.len(), 1);
}

#[test]
fn error_recovery_dont_panic_on_reduce_at_eof() {
    let mut errors = vec![];
    util::test(|v| error_recovery_pull_182::parse_Item(&mut errors, v), "1+", ());

    assert_eq!(errors.len(), 1);
}

#[test]
fn issue_55_test1() {
    // Issue 55 caused us to either accept NO assoc types or assoc
    // types both before and after, so check that we can parse with
    // assoc types on either side.

    let (a, b, c) = issue_55::parse_E("{ type X; type Y; enum Z { } }").unwrap();
    assert_eq!(a, vec!["X", "Y"]);
    assert_eq!(b, "Z");
    assert!(c.is_empty());

    let (a, b, c) = issue_55::parse_E("{ enum Z { } type X; type Y; }").unwrap();
    assert!(a.is_empty());
    assert_eq!(b, "Z");
    assert_eq!(c, vec!["X", "Y"]);
}

#[test]
fn unit_test1() {
    assert!(unit::parse_Expr("3 + 4 * 5").is_ok());
}

#[test]
fn unit_test2() {
    assert!(unit::parse_Expr("3 + +").is_err());
}

#[test]
fn generics_issue_104_test1() {
    // The real thing `generics_issue_104` is testing is that the code
    // *compiles*, even though the type parameter `T` does not appear
    // in any of the arguments.
    assert!(generics_issue_104::parse_Schema::<()>("grammar { foo }").is_ok());
}

#[test]
fn test_match_section() {
    assert!(match_section::parse_Query("SELECT foo").is_ok());
    assert!(match_section::parse_Query("select foo").is_ok());
    assert!(match_section::parse_Query("INSERT foo").is_ok());
    assert!(match_section::parse_Query("UPDATE foo").is_ok());
    assert!(match_section::parse_Query("UPDATE update").is_err());
}
<|endoftext|>


<commit_before>//
//
//
#[allow(dead_code)]
#[path="../src/protocol.rs"]
mod protocol;

use protocol::Token;

pub fn dump_token_stream<R: ::std::io::Read>(reader: R)
{
    let mut s = protocol::Reader::new(reader);
    while let Some(v) = s.read_ent()
    {
        match v
        {
        Token::Symbol(s) => println!("SYM {}", s),
        Token::Ident(s) => println!("IDENT {}", s),
        Token::Lifetime(s) => println!("LIFETIME {}", s),
        Token::String(s) => println!("STRING {:?}", s),
        Token::ByteString(s) => println!("BYTESTRING {:x?}", s),
        Token::Char(c) => println!("CHAR {:?}", c),
        Token::Unsigned(val, ty) => println!("UNSIGNED {val:?} ty={ty}", val=val, ty=ty),
        Token::Signed(val, ty) => println!("SIGNED {val:?} ty={ty}", val=val, ty=ty),
        Token::Float(val, ty) => println!("FLOAT {val:?} ty={ty}", val=val, ty=ty),
        }
    }
}

fn main()
{
    // Hacky argument parsing
    let mut is_output = false;
    for a in ::std::env::args().skip(1)
    {
        if !a.starts_with("-")
        {
            // Free
            // TODO: Error?
        }
        else if !a.starts_with("--")
        {
            // Short
            for c in a.chars().skip(1)
            {
                match c
                {
                _ => {},
                }
            }
        }
        else if a != "--"
        {
            // Long
            match &a[..]
            {
            "--is-output" => is_output = true,
            _ => {},
            }
        }
        else
        {
            // All free
        }
    }

    // If --is-output was passed, consume the leading NUL byte
    // - Maybe this should just be an empty symbol instead of a single NUL?
    if is_output
    {
        use std::io::Read;
        let mut b = [0];
        ::std::io::stdin().read_exact(&mut b).unwrap();
        assert_eq!(b[0], 0);
    }
    //
    dump_token_stream(::std::io::stdin().lock());
}
<commit_msg>libproc_macro - Tweak the `dump` tool<commit_after>//
//
//
#[allow(dead_code)]
#[path="../src/protocol.rs"]
mod protocol;

use protocol::Token;

pub fn dump_token_stream<R: ::std::io::Read>(reader: R)
{
    let mut s = protocol::Reader::new(reader);
    while let Some(v) = s.read_ent()
    {
        match v
        {
        Token::Symbol(s) => println!("SYM {}", s),
        Token::Ident(s) => println!("IDENT {}", s),
        Token::Lifetime(s) => println!("LIFETIME {}", s),
        Token::String(s) => println!("STRING {:?}", s),
        Token::ByteString(s) => println!("BYTESTRING {:x?}", s),
        Token::Char(c) => println!("CHAR {:?}", c),
        Token::Unsigned(val, ty) => println!("UNSIGNED {val:?} ty={ty}", val=val, ty=ty),
        Token::Signed(val, ty) => println!("SIGNED {val:?} ty={ty}", val=val, ty=ty),
        Token::Float(val, ty) => println!("FLOAT {val:?} ty={ty}", val=val, ty=ty),
        }
    }
}

pub fn dump_token_stream_pretty<R: ::std::io::Read>(reader: R)
{
    let mut s = protocol::Reader::new(reader);
    while let Some(v) = s.read_ent()
    {
        match v
        {
        Token::Symbol(s) => print!("{} ", s),
        Token::Ident(s) => print!("{} ", s),
        Token::Lifetime(s) => print!("'{} ", s),
        Token::String(s) => print!("{:?}", s),
        Token::ByteString(s) => print!("{:x?}", s),
        Token::Char(c) => print!("'{:?}'", c),
        Token::Unsigned(val, ty) => print!("{val:?} /*ty={ty}*/", val=val, ty=ty),
        Token::Signed(val, ty) => print!("{val:?} /*ty={ty}*/", val=val, ty=ty),
        Token::Float(val, ty) => print!("{val:?} /*ty={ty}*/", val=val, ty=ty),
        }
    }
    println!("");
}

fn main()
{
    // Hacky argument parsing
    let mut is_pretty = false;
    let mut is_output = false;
    for a in ::std::env::args().skip(1)
    {
        if !a.starts_with("-")
        {
            // Free
            // TODO: Error?
            panic!("Unknown free argument {:?}", a);
        }
        else if !a.starts_with("--")
        {
            // Short
            for c in a.chars().skip(1)
            {
                match c
                {
                _ => panic!("Unknown short argument `-{}`", c),
                }
            }
        }
        else if a != "--"
        {
            // Long
            match &a[..]
            {
            "--is-output" => is_output = true,
            "--pretty" => is_pretty = true,
            _ => panic!("Unknown argument `{}`", a),
            }
        }
        else
        {
            // All free
        }
    }

    // If --is-output was passed, consume the leading NUL byte
    // - Maybe this should just be an empty symbol instead of a single NUL?
    if is_output
    {
        use std::io::Read;
        let mut b = [0];
        ::std::io::stdin().read_exact(&mut b).unwrap();
        assert_eq!(b[0], 0);
    }
    //
    if is_pretty {
        dump_token_stream_pretty(::std::io::stdin().lock());
    }
    else {
        dump_token_stream(::std::io::stdin().lock());
    }
}
<|endoftext|>


<commit_before>// Automatically generated rust module for 'test_root_pb.proto' file

#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
#![allow(unknown_lints)]
#![allow(clippy)]
#![cfg_attr(rustfmt, rustfmt_skip)]

use std::io::Write;
use quick_protobuf::{MessageRead, MessageWrite, BytesReader, Writer, Result};
use quick_protobuf::sizeofs::*;
use super::*;

#[derive(Debug, Default, PartialEq, Clone)]
pub struct Root {
    pub nested: Vec<mod_Root::Nested>,
}

impl<'a> MessageRead<'a> for Root {
    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
        let mut msg = Self::default();
        while !r.is_eof() {
            match r.next_tag(bytes) {
                Ok(10) => msg.nested.push(r.read_message::<mod_Root::Nested>(bytes)?),
                Ok(t) => { r.read_unknown(bytes, t)?; }
                Err(e) => return Err(e),
            }
        }
        Ok(msg)
    }
}

impl MessageWrite for Root {
    fn get_size(&self) -> usize {
        0
        + self.nested.iter().map(|s| 1 + sizeof_len((s).get_size())).sum::<usize>()
    }

    fn write_message<W: Write>(&self, w: &mut Writer<W>) -> Result<()> {
        for s in &self.nested { w.write_with_tag(10, |w| w.write_message(s))?; }
        Ok(())
    }
}

pub mod mod_Root {

use super::*;

#[derive(Debug, Default, PartialEq, Clone)]
pub struct Nested { }

impl<'a> MessageRead<'a> for Nested {
    fn from_reader(r: &mut BytesReader, _: &[u8]) -> Result<Self> {
        r.read_to_end();
        Ok(Self::default())
    }
}

impl MessageWrite for Nested { }

}

<commit_msg>Delete test_root_pb.rs<commit_after><|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Helpers for different FFI pointer kinds that Gecko's FFI layer uses.

use servo_arc::{Arc, RawOffsetArc};
use std::marker::PhantomData;
use std::mem::{forget, transmute};
use std::ops::{Deref, DerefMut};
use std::ptr;

/// Indicates that a given Servo type has a corresponding Gecko FFI type.
pub unsafe trait HasFFI : Sized + 'static {
    /// The corresponding Gecko type that this rust type represents.
    ///
    /// See the examples in `components/style/gecko/conversions.rs`.
    type FFIType: Sized;
}

/// Indicates that a given Servo type has the same layout as the corresponding
/// `HasFFI::FFIType` type.
pub unsafe trait HasSimpleFFI : HasFFI {
    #[inline]
    /// Given a Servo-side reference, converts it to an FFI-safe reference which
    /// can be passed to Gecko.
    ///
    /// &ServoType -> &GeckoType
    fn as_ffi(&self) -> &Self::FFIType {
        unsafe { transmute(self) }
    }
    #[inline]
    /// Given a Servo-side mutable reference, converts it to an FFI-safe mutable
    /// reference which can be passed to Gecko.
    ///
    /// &mut ServoType -> &mut GeckoType
    fn as_ffi_mut(&mut self) -> &mut Self::FFIType {
        unsafe { transmute(self) }
    }
    #[inline]
    /// Given an FFI-safe reference obtained from Gecko converts it to a
    /// Servo-side reference.
    ///
    /// &GeckoType -> &ServoType
    fn from_ffi(ffi: &Self::FFIType) -> &Self {
        unsafe { transmute(ffi) }
    }
    #[inline]
    /// Given an FFI-safe mutable reference obtained from Gecko converts it to a
    /// Servo-side mutable reference.
    ///
    /// &mut GeckoType -> &mut ServoType
    fn from_ffi_mut(ffi: &mut Self::FFIType) -> &mut Self {
        unsafe { transmute(ffi) }
    }
}

/// Indicates that the given Servo type is passed over FFI
/// as a Box
pub unsafe trait HasBoxFFI : HasSimpleFFI {
    #[inline]
    /// Converts a borrowed Arc to a borrowed FFI reference.
    ///
    /// &Arc<ServoType> -> &GeckoType
    fn into_ffi(self: Box<Self>) -> Owned<Self::FFIType> {
        unsafe { transmute(self) }
    }
}

/// Helper trait for conversions between FFI Strong/Borrowed types and Arcs
///
/// Should be implemented by types which are passed over FFI as Arcs via Strong
/// and Borrowed.
///
/// In this case, the FFIType is the rough equivalent of ArcInner<Self>.
pub unsafe trait HasArcFFI : HasFFI {
    // these methods can't be on Borrowed because it leads to an unspecified
    // impl parameter
    /// Artificially increments the refcount of a (possibly null) borrowed Arc
    /// over FFI.
    unsafe fn addref_opt(ptr: Option<&Self::FFIType>) {
        forget(Self::arc_from_borrowed(&ptr).clone())
    }

    /// Given a (possibly null) borrowed FFI reference, decrements the refcount.
    /// Unsafe since it doesn't consume the backing Arc. Run it only when you
    /// know that a strong reference to the backing Arc is disappearing
    /// (usually on the C++ side) without running the Arc destructor.
    unsafe fn release_opt(ptr: Option<&Self::FFIType>) {
        if let Some(arc) = Self::arc_from_borrowed(&ptr) {
            let _: RawOffsetArc<_> = ptr::read(arc as *const RawOffsetArc<_>);
        }
    }

    /// Artificially increments the refcount of a borrowed Arc over FFI.
    unsafe fn addref(ptr: &Self::FFIType) {
        forget(Self::as_arc(&ptr).clone())
    }

    /// Given a non-null borrowed FFI reference, decrements the refcount.
    /// Unsafe since it doesn't consume the backing Arc. Run it only when you
    /// know that a strong reference to the backing Arc is disappearing
    /// (usually on the C++ side) without running the Arc destructor.
    unsafe fn release(ptr: &Self::FFIType) {
        let _: RawOffsetArc<_> = ptr::read(Self::as_arc(&ptr) as *const RawOffsetArc<_>);
    }
    #[inline]
    /// Converts a borrowed FFI reference to a borrowed Arc.
    ///
    /// &GeckoType -> &Arc<ServoType>
    fn as_arc<'a>(ptr: &'a &Self::FFIType) -> &'a RawOffsetArc<Self> {
        debug_assert!(!(ptr as *const _).is_null());
        unsafe {
            transmute::<&&Self::FFIType, &RawOffsetArc<Self>>(ptr)
        }
    }

    #[inline]
    /// Converts a borrowed Arc to a borrowed FFI reference.
    ///
    /// &Arc<ServoType> -> &GeckoType
    fn arc_as_borrowed<'a>(arc: &'a RawOffsetArc<Self>) -> &'a &Self::FFIType {
        unsafe {
            transmute::<&RawOffsetArc<Self>, &&Self::FFIType>(arc)
        }
    }

    #[inline]
    /// Converts a borrowed nullable FFI reference to a borrowed Arc.
    ///
    /// &GeckoType -> &Arc<ServoType>
    fn arc_from_borrowed<'a>(ptr: &'a Option<&Self::FFIType>) -> Option<&'a RawOffsetArc<Self>> {
        unsafe {
            if let Some(ref reference) = *ptr {
                Some(transmute::<&&Self::FFIType, &RawOffsetArc<_>>(reference))
            } else {
                None
            }
        }
    }
}

#[repr(C)]
/// Gecko-FFI-safe Arc (T is an ArcInner).
///
/// This can be null.
///
/// Leaks on drop. Please don't drop this.
pub struct Strong<GeckoType> {
    ptr: *const GeckoType,
    _marker: PhantomData<GeckoType>,
}

impl<GeckoType> Strong<GeckoType> {
    #[inline]
    /// Returns whether this reference is null.
    pub fn is_null(&self) -> bool {
        self.ptr.is_null()
    }

    #[inline]
    /// Given a non-null strong FFI reference, converts it into a servo-side
    /// Arc.
    ///
    /// Panics on null.
    ///
    /// Strong<GeckoType> -> Arc<ServoType>
    pub fn into_arc<ServoType>(self) -> RawOffsetArc<ServoType>
        where ServoType: HasArcFFI<FFIType = GeckoType>,
    {
        self.into_arc_opt().unwrap()
    }

    #[inline]
    /// Given a strong FFI reference,
    /// converts it into a servo-side Arc
    /// Returns None on null.
    ///
    /// Strong<GeckoType> -> Arc<ServoType>
    pub fn into_arc_opt<ServoType>(self) -> Option<RawOffsetArc<ServoType>>
        where ServoType: HasArcFFI<FFIType = GeckoType>,
    {
        if self.is_null() {
            None
        } else {
            unsafe { Some(transmute(self)) }
        }
    }

    #[inline]
    /// Given a reference to a strong FFI reference, converts it to a reference
    /// to a servo-side Arc.
    ///
    /// Returns None on null.
    ///
    /// Strong<GeckoType> -> Arc<ServoType>
    pub fn as_arc_opt<ServoType>(&self) -> Option<&RawOffsetArc<ServoType>>
        where ServoType: HasArcFFI<FFIType = GeckoType>,
    {
        if self.is_null() {
            None
        } else {
            unsafe { Some(transmute(self)) }
        }
    }

    #[inline]
    /// Produces a null strong FFI reference.
    pub fn null() -> Self {
        unsafe { transmute(ptr::null::<GeckoType>()) }
    }
}

/// A few helpers implemented on top of Arc<ServoType> to make it more
/// comfortable to use and write safe code with.
pub unsafe trait FFIArcHelpers {
    /// The Rust FFI type that we're implementing methods for.
    type Inner: HasArcFFI;

    /// Converts an Arc into a strong FFI reference.
    ///
    /// Arc<ServoType> -> Strong<GeckoType>
    fn into_strong(self) -> Strong<<Self::Inner as HasFFI>::FFIType>;

    /// Produces a borrowed FFI reference by borrowing an Arc.
    ///
    /// &Arc<ServoType> -> &GeckoType
    ///
    /// Then the `arc_as_borrowed` method can go away.
    fn as_borrowed(&self) -> &<Self::Inner as HasFFI>::FFIType;
}

unsafe impl<T: HasArcFFI> FFIArcHelpers for RawOffsetArc<T> {
    type Inner = T;

    #[inline]
    fn into_strong(self) -> Strong<T::FFIType> {
        unsafe { transmute(self) }
    }

    #[inline]
    fn as_borrowed(&self) -> &T::FFIType {
        unsafe { &*(&**self as *const T as *const T::FFIType) }
    }
}

unsafe impl<T: HasArcFFI> FFIArcHelpers for Arc<T> {
    type Inner = T;

    #[inline]
    fn into_strong(self) -> Strong<T::FFIType> {
        Arc::into_raw_offset(self).into_strong()
    }

    #[inline]
    fn as_borrowed(&self) -> &T::FFIType {
        unsafe { &*(&**self as *const T as *const T::FFIType) }
    }
}

#[repr(C)]
#[derive(Debug)]
/// Gecko-FFI-safe owned pointer.
///
/// Cannot be null, and leaks on drop, so needs to be converted into a rust-side
/// `Box` before.
pub struct Owned<GeckoType> {
    ptr: *mut GeckoType,
    _marker: PhantomData<GeckoType>,
}

impl<GeckoType> Owned<GeckoType> {
    /// Gets this `Owned` type as a `Box<ServoType>`.
    pub fn into_box<ServoType>(self) -> Box<ServoType>
        where ServoType: HasBoxFFI<FFIType = GeckoType>,
    {
        unsafe { transmute(self) }
    }

    /// Converts this instance to a (non-null) instance of `OwnedOrNull`.
    pub fn maybe(self) -> OwnedOrNull<GeckoType> {
        unsafe { transmute(self) }
    }
}

impl<GeckoType> Deref for Owned<GeckoType> {
    type Target = GeckoType;
    fn deref(&self) -> &GeckoType {
        unsafe { &*self.ptr }
    }
}

impl<GeckoType> DerefMut for Owned<GeckoType> {
    fn deref_mut(&mut self) -> &mut GeckoType {
        unsafe { &mut *self.ptr }
    }
}

#[repr(C)]
/// Gecko-FFI-safe owned pointer.
///
/// Can be null, and just as `Owned` leaks on `Drop`.
pub struct OwnedOrNull<GeckoType> {
    ptr: *mut GeckoType,
    _marker: PhantomData<GeckoType>,
}

impl<GeckoType> OwnedOrNull<GeckoType> {
    /// Returns whether this pointer is null.
    #[inline]
    pub fn is_null(&self) -> bool {
        self.ptr.is_null()
    }

    /// Returns an owned pointer if this is non-null, and `None` otherwise.
    pub fn into_box_opt<ServoType>(self) -> Option<Box<ServoType>>
        where ServoType: HasBoxFFI<FFIType = GeckoType>,
    {
        if self.is_null() {
            None
        } else {
            Some(unsafe { transmute(self) })
        }
    }

    /// Returns an `Owned<GeckoType>` if non-null, `None` otherwise.
    pub fn into_owned_opt(self) -> Option<Owned<GeckoType>> {
        if self.is_null() {
            None
        } else {
            Some(unsafe { transmute(self) })
        }
    }

    /// Gets a immutable reference to the underlying Gecko type, or `None` if
    /// null.
    pub fn borrow(&self) -> Option<&GeckoType> {
        unsafe { transmute(self) }
    }

    /// Gets a mutable reference to the underlying Gecko type, or `None` if
    /// null.
    pub fn borrow_mut(&self) -> Option<&mut GeckoType> {
        unsafe { transmute(self) }
    }
}
<commit_msg>style: Remove pointless assertion.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Helpers for different FFI pointer kinds that Gecko's FFI layer uses.

use servo_arc::{Arc, RawOffsetArc};
use std::marker::PhantomData;
use std::mem::{forget, transmute};
use std::ops::{Deref, DerefMut};
use std::ptr;

/// Indicates that a given Servo type has a corresponding Gecko FFI type.
pub unsafe trait HasFFI : Sized + 'static {
    /// The corresponding Gecko type that this rust type represents.
    ///
    /// See the examples in `components/style/gecko/conversions.rs`.
    type FFIType: Sized;
}

/// Indicates that a given Servo type has the same layout as the corresponding
/// `HasFFI::FFIType` type.
pub unsafe trait HasSimpleFFI : HasFFI {
    #[inline]
    /// Given a Servo-side reference, converts it to an FFI-safe reference which
    /// can be passed to Gecko.
    ///
    /// &ServoType -> &GeckoType
    fn as_ffi(&self) -> &Self::FFIType {
        unsafe { transmute(self) }
    }
    #[inline]
    /// Given a Servo-side mutable reference, converts it to an FFI-safe mutable
    /// reference which can be passed to Gecko.
    ///
    /// &mut ServoType -> &mut GeckoType
    fn as_ffi_mut(&mut self) -> &mut Self::FFIType {
        unsafe { transmute(self) }
    }
    #[inline]
    /// Given an FFI-safe reference obtained from Gecko converts it to a
    /// Servo-side reference.
    ///
    /// &GeckoType -> &ServoType
    fn from_ffi(ffi: &Self::FFIType) -> &Self {
        unsafe { transmute(ffi) }
    }
    #[inline]
    /// Given an FFI-safe mutable reference obtained from Gecko converts it to a
    /// Servo-side mutable reference.
    ///
    /// &mut GeckoType -> &mut ServoType
    fn from_ffi_mut(ffi: &mut Self::FFIType) -> &mut Self {
        unsafe { transmute(ffi) }
    }
}

/// Indicates that the given Servo type is passed over FFI
/// as a Box
pub unsafe trait HasBoxFFI : HasSimpleFFI {
    #[inline]
    /// Converts a borrowed Arc to a borrowed FFI reference.
    ///
    /// &Arc<ServoType> -> &GeckoType
    fn into_ffi(self: Box<Self>) -> Owned<Self::FFIType> {
        unsafe { transmute(self) }
    }
}

/// Helper trait for conversions between FFI Strong/Borrowed types and Arcs
///
/// Should be implemented by types which are passed over FFI as Arcs via Strong
/// and Borrowed.
///
/// In this case, the FFIType is the rough equivalent of ArcInner<Self>.
pub unsafe trait HasArcFFI : HasFFI {
    // these methods can't be on Borrowed because it leads to an unspecified
    // impl parameter
    /// Artificially increments the refcount of a (possibly null) borrowed Arc
    /// over FFI.
    unsafe fn addref_opt(ptr: Option<&Self::FFIType>) {
        forget(Self::arc_from_borrowed(&ptr).clone())
    }

    /// Given a (possibly null) borrowed FFI reference, decrements the refcount.
    /// Unsafe since it doesn't consume the backing Arc. Run it only when you
    /// know that a strong reference to the backing Arc is disappearing
    /// (usually on the C++ side) without running the Arc destructor.
    unsafe fn release_opt(ptr: Option<&Self::FFIType>) {
        if let Some(arc) = Self::arc_from_borrowed(&ptr) {
            let _: RawOffsetArc<_> = ptr::read(arc as *const RawOffsetArc<_>);
        }
    }

    /// Artificially increments the refcount of a borrowed Arc over FFI.
    unsafe fn addref(ptr: &Self::FFIType) {
        forget(Self::as_arc(&ptr).clone())
    }

    /// Given a non-null borrowed FFI reference, decrements the refcount.
    /// Unsafe since it doesn't consume the backing Arc. Run it only when you
    /// know that a strong reference to the backing Arc is disappearing
    /// (usually on the C++ side) without running the Arc destructor.
    unsafe fn release(ptr: &Self::FFIType) {
        let _: RawOffsetArc<_> = ptr::read(Self::as_arc(&ptr) as *const RawOffsetArc<_>);
    }
    #[inline]
    /// Converts a borrowed FFI reference to a borrowed Arc.
    ///
    /// &GeckoType -> &Arc<ServoType>
    fn as_arc<'a>(ptr: &'a &Self::FFIType) -> &'a RawOffsetArc<Self> {
        unsafe {
            transmute::<&&Self::FFIType, &RawOffsetArc<Self>>(ptr)
        }
    }

    #[inline]
    /// Converts a borrowed Arc to a borrowed FFI reference.
    ///
    /// &Arc<ServoType> -> &GeckoType
    fn arc_as_borrowed<'a>(arc: &'a RawOffsetArc<Self>) -> &'a &Self::FFIType {
        unsafe {
            transmute::<&RawOffsetArc<Self>, &&Self::FFIType>(arc)
        }
    }

    #[inline]
    /// Converts a borrowed nullable FFI reference to a borrowed Arc.
    ///
    /// &GeckoType -> &Arc<ServoType>
    fn arc_from_borrowed<'a>(ptr: &'a Option<&Self::FFIType>) -> Option<&'a RawOffsetArc<Self>> {
        unsafe {
            if let Some(ref reference) = *ptr {
                Some(transmute::<&&Self::FFIType, &RawOffsetArc<_>>(reference))
            } else {
                None
            }
        }
    }
}

#[repr(C)]
/// Gecko-FFI-safe Arc (T is an ArcInner).
///
/// This can be null.
///
/// Leaks on drop. Please don't drop this.
pub struct Strong<GeckoType> {
    ptr: *const GeckoType,
    _marker: PhantomData<GeckoType>,
}

impl<GeckoType> Strong<GeckoType> {
    #[inline]
    /// Returns whether this reference is null.
    pub fn is_null(&self) -> bool {
        self.ptr.is_null()
    }

    #[inline]
    /// Given a non-null strong FFI reference, converts it into a servo-side
    /// Arc.
    ///
    /// Panics on null.
    ///
    /// Strong<GeckoType> -> Arc<ServoType>
    pub fn into_arc<ServoType>(self) -> RawOffsetArc<ServoType>
        where ServoType: HasArcFFI<FFIType = GeckoType>,
    {
        self.into_arc_opt().unwrap()
    }

    #[inline]
    /// Given a strong FFI reference,
    /// converts it into a servo-side Arc
    /// Returns None on null.
    ///
    /// Strong<GeckoType> -> Arc<ServoType>
    pub fn into_arc_opt<ServoType>(self) -> Option<RawOffsetArc<ServoType>>
        where ServoType: HasArcFFI<FFIType = GeckoType>,
    {
        if self.is_null() {
            None
        } else {
            unsafe { Some(transmute(self)) }
        }
    }

    #[inline]
    /// Given a reference to a strong FFI reference, converts it to a reference
    /// to a servo-side Arc.
    ///
    /// Returns None on null.
    ///
    /// Strong<GeckoType> -> Arc<ServoType>
    pub fn as_arc_opt<ServoType>(&self) -> Option<&RawOffsetArc<ServoType>>
        where ServoType: HasArcFFI<FFIType = GeckoType>,
    {
        if self.is_null() {
            None
        } else {
            unsafe { Some(transmute(self)) }
        }
    }

    #[inline]
    /// Produces a null strong FFI reference.
    pub fn null() -> Self {
        unsafe { transmute(ptr::null::<GeckoType>()) }
    }
}

/// A few helpers implemented on top of Arc<ServoType> to make it more
/// comfortable to use and write safe code with.
pub unsafe trait FFIArcHelpers {
    /// The Rust FFI type that we're implementing methods for.
    type Inner: HasArcFFI;

    /// Converts an Arc into a strong FFI reference.
    ///
    /// Arc<ServoType> -> Strong<GeckoType>
    fn into_strong(self) -> Strong<<Self::Inner as HasFFI>::FFIType>;

    /// Produces a borrowed FFI reference by borrowing an Arc.
    ///
    /// &Arc<ServoType> -> &GeckoType
    ///
    /// Then the `arc_as_borrowed` method can go away.
    fn as_borrowed(&self) -> &<Self::Inner as HasFFI>::FFIType;
}

unsafe impl<T: HasArcFFI> FFIArcHelpers for RawOffsetArc<T> {
    type Inner = T;

    #[inline]
    fn into_strong(self) -> Strong<T::FFIType> {
        unsafe { transmute(self) }
    }

    #[inline]
    fn as_borrowed(&self) -> &T::FFIType {
        unsafe { &*(&**self as *const T as *const T::FFIType) }
    }
}

unsafe impl<T: HasArcFFI> FFIArcHelpers for Arc<T> {
    type Inner = T;

    #[inline]
    fn into_strong(self) -> Strong<T::FFIType> {
        Arc::into_raw_offset(self).into_strong()
    }

    #[inline]
    fn as_borrowed(&self) -> &T::FFIType {
        unsafe { &*(&**self as *const T as *const T::FFIType) }
    }
}

#[repr(C)]
#[derive(Debug)]
/// Gecko-FFI-safe owned pointer.
///
/// Cannot be null, and leaks on drop, so needs to be converted into a rust-side
/// `Box` before.
pub struct Owned<GeckoType> {
    ptr: *mut GeckoType,
    _marker: PhantomData<GeckoType>,
}

impl<GeckoType> Owned<GeckoType> {
    /// Gets this `Owned` type as a `Box<ServoType>`.
    pub fn into_box<ServoType>(self) -> Box<ServoType>
        where ServoType: HasBoxFFI<FFIType = GeckoType>,
    {
        unsafe { transmute(self) }
    }

    /// Converts this instance to a (non-null) instance of `OwnedOrNull`.
    pub fn maybe(self) -> OwnedOrNull<GeckoType> {
        unsafe { transmute(self) }
    }
}

impl<GeckoType> Deref for Owned<GeckoType> {
    type Target = GeckoType;
    fn deref(&self) -> &GeckoType {
        unsafe { &*self.ptr }
    }
}

impl<GeckoType> DerefMut for Owned<GeckoType> {
    fn deref_mut(&mut self) -> &mut GeckoType {
        unsafe { &mut *self.ptr }
    }
}

#[repr(C)]
/// Gecko-FFI-safe owned pointer.
///
/// Can be null, and just as `Owned` leaks on `Drop`.
pub struct OwnedOrNull<GeckoType> {
    ptr: *mut GeckoType,
    _marker: PhantomData<GeckoType>,
}

impl<GeckoType> OwnedOrNull<GeckoType> {
    /// Returns whether this pointer is null.
    #[inline]
    pub fn is_null(&self) -> bool {
        self.ptr.is_null()
    }

    /// Returns an owned pointer if this is non-null, and `None` otherwise.
    pub fn into_box_opt<ServoType>(self) -> Option<Box<ServoType>>
        where ServoType: HasBoxFFI<FFIType = GeckoType>,
    {
        if self.is_null() {
            None
        } else {
            Some(unsafe { transmute(self) })
        }
    }

    /// Returns an `Owned<GeckoType>` if non-null, `None` otherwise.
    pub fn into_owned_opt(self) -> Option<Owned<GeckoType>> {
        if self.is_null() {
            None
        } else {
            Some(unsafe { transmute(self) })
        }
    }

    /// Gets a immutable reference to the underlying Gecko type, or `None` if
    /// null.
    pub fn borrow(&self) -> Option<&GeckoType> {
        unsafe { transmute(self) }
    }

    /// Gets a mutable reference to the underlying Gecko type, or `None` if
    /// null.
    pub fn borrow_mut(&self) -> Option<&mut GeckoType> {
        unsafe { transmute(self) }
    }
}
<|endoftext|>