use std::cmp::Ordering::{Equal, Greater, Less};
use std::mem::{transmute};
use audio::{Audio};
use bitmap::{Bitmap};
use file::{File};
use repr;
pub use repr::Type;
pub trait GenericNode<'a> {
fn get(&self, name: &str) -> Option<Node<'a>>;
fn dtype(&self) -> Type;
fn string(&self) -> Option<&'a str>;
fn integer(&self) -> Option<i64>;
fn float(&self) -> Option<f64>;
fn vector(&self) -> Option<(i32, i32)>;
fn audio(&self) -> Option<Audio<'a>>;
fn bitmap(&self) -> Option<Bitmap<'a>>;
}
#[derive(Clone, Copy)]
pub struct Node<'a> {
data: &'a repr::Node,
file: &'a File,
}
impl<'a> Node<'a> {
#[inline]
pub unsafe fn construct(data: &'a repr::Node, file: &'a File) -> Node<'a> {
Node { data: data, file: file }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.count == 0
}
#[inline]
pub fn name(&self) -> &'a str {
unsafe { self.file.get_str(self.data.name) }
}
#[inline]
pub fn iter(&self) -> Nodes<'a> {
let data = unsafe { self.file.get_node(self.data.children) };
Nodes {
data: data,
count: self.data.count,
file: self.file,
}
}
}
impl<'a> GenericNode<'a> for Node<'a> {
#[inline]
fn get(&self, name: &str) -> Option<Node<'a>> {
let mut data = unsafe { self.file.get_node(self.data.children) as *const repr::Node };
let mut count = self.data.count as isize;
while count > 0 {
let half = count / 2;
let temp = unsafe { data.offset(half) };
let other = unsafe { self.file.get_str((*temp).name) };
match other.cmp(name) {
Less => {
data = unsafe { temp.offset(1) };
count -= half + 1;
},
Equal => return Some(Node {
data: unsafe { &*temp },
file: self.file,
}),
Greater => count = half,
}
}
None
}
#[inline]
fn dtype(&self) -> Type {
match self.data.dtype {
0 => Type::Empty,
1 => Type::Integer,
2 => Type::Float,
3 => Type::String,
4 => Type::Vector,
5 => Type::Bitmap,
6 => Type::Audio,
_ => Type::Empty
}
}
#[inline]
fn string(&self) -> Option<&'a str> {
match self.dtype() {
Type::String => Some(unsafe {
self.file.get_str(transmute::<_, repr::String>(self.data.data).index)
}),
_ => None,
}
}
#[inline]
fn integer(&self) -> Option<i64> {
match self.dtype() {
Type::Integer => Some(unsafe { transmute::<_, repr::Integer>(self.data.data).value }),
_ => None,
}
}
#[inline]
fn float(&self) -> Option<f64> {
match self.dtype() {
Type::Float => Some(unsafe { transmute::<_, repr::Float>(self.data.data).value }),
_ => None,
}
}
#[inline]
fn vector(&self) -> Option<(i32, i32)> {
match self.dtype() {
Type::Vector => Some(unsafe {
let vec = transmute::<_, repr::Vector>(self.data.data);
(vec.x, vec.y)
}),
_ => None,
}
}
#[inline]
fn audio(&self) -> Option<Audio<'a>> {
match self.dtype() {
Type::Audio => Some(unsafe {
let audio = transmute::<_, repr::Audio>(self.data.data);
Audio::construct(self.file.get_audio(audio.index, audio.length))
}),
_ => None,
}
}
#[inline]
fn bitmap(&self) -> Option<Bitmap<'a>> {
match self.dtype() {
Type::Bitmap => Some(unsafe {
let bitmap = transmute::<_, repr::Bitmap>(self.data.data);
Bitmap::construct(self.file.get_bitmap(bitmap.index), bitmap.width, bitmap.height)
}),
_ => None,
}
}
}
impl<'a> GenericNode<'a> for Option<Node<'a>> {
#[inline]
fn get(&self, name: &str) -> Option<Node<'a>> {
match self {
&Some(n) => n.get(name),
&None => None,
}
}
#[inline]
fn dtype(&self) -> Type {
match self {
&Some(n) => n.dtype(),
&None => Type::Empty,
}
}
#[inline]
fn string(&self) -> Option<&'a str> {
match self {
&Some(n) => n.string(),
&None => None,
}
}
#[inline]
fn integer(&self) -> Option<i64> {
match self {
&Some(n) => n.integer(),
&None => None,
}
}
#[inline]
fn float(&self) -> Option<f64> {
match self {
&Some(n) => n.float(),
&None => None,
}
}
#[inline]
fn vector(&self) -> Option<(i32, i32)> {
match self {
&Some(n) => n.vector(),
&None => None,
}
}
#[inline]
fn audio(&self) -> Option<Audio<'a>> {
match self {
&Some(n) => n.audio(),
&None => None,
}
}
#[inline]
fn bitmap(&self) -> Option<Bitmap<'a>> {
match self {
&Some(n) => n.bitmap(),
&None => None,
}
}
}
impl<'a> PartialEq for Node<'a> {
#[inline]
fn eq(&self, other: &Node) -> bool {
self.data as *const repr::Node == other.data as *const repr::Node
}
}
impl<'a> Eq for Node<'a> {}
pub struct Nodes<'a> {
data: *const repr::Node,
count: u16,
file: &'a File,
}
impl<'a> Iterator for Nodes<'a> {
type Item = Node<'a>;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.count as usize, Some(self.count as usize))
}
#[inline]
fn next(&mut self) -> Option<Node<'a>> {
match self.count {
0 => None,
_ => {
self.count -= 1;
let node = Node {
data: unsafe { &*self.data },
file: self.file
};
self.data = unsafe { self.data.offset(1) };
Some(node)
}
}
}
}