use std::result;
use std::convert;
use std::error;
use std::fmt::{self, Display, Formatter, Debug};
use std::ffi::CStr;
use object::{Object, List, ListIter};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Endianness{
LittleEndian,
BigEndian,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum ObjectType{
Empty = 0,
Mesh = 1,
Curve = 2,
Surf = 3,
Font = 4,
MBall = 5,
Lamp = 10,
Camera = 11,
Wave = 21,
Lattice = 22,
Armature = 25,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum PropertyType{
String = 0,
Int = 1,
Float = 2,
Array = 5,
Group = 6,
Id = 7,
Double = 8,
IdArray = 9,
NumTypes = 10,
}
#[derive(Debug, Clone)]
pub enum IdProperty<'a>{
String(Object<'a>),
Int(Object<'a>),
Float(Object<'a>),
Array(Object<'a>),
Group(Object<'a>),
Id(Object<'a>),
Double(Object<'a>),
IdArray(Object<'a>),
}
impl<'a> IdProperty<'a>{
fn new(obj: Object<'a>) -> Result<IdProperty<'a>>{
if obj.structure().name() != "IDProperty"{
return Err(Error::from("Object is not an IDProperty".to_owned()))
}else{
let p = match obj.get::<PropertyType>("type").unwrap(){
PropertyType::String => IdProperty::String(obj),
PropertyType::Int => IdProperty::Int(obj),
PropertyType::Float => IdProperty::Float(obj),
PropertyType::Array => IdProperty::Array(obj),
PropertyType::Group => IdProperty::Group(obj),
PropertyType::Id => IdProperty::Id(obj),
PropertyType::Double => IdProperty::Double(obj),
PropertyType::IdArray => IdProperty::IdArray(obj),
PropertyType::NumTypes => return Err(Error("Invalid IDProperty type".to_string())),
};
Ok(p)
}
}
}
impl<'a> IdProperty<'a>{
pub fn ty(&self) -> PropertyType{
match self{
IdProperty::String(_) => PropertyType::String,
IdProperty::Int(_) => PropertyType::Int,
IdProperty::Float(_) => PropertyType::Float,
IdProperty::Array(_) => PropertyType::Array,
IdProperty::Group(_) => PropertyType::Group,
IdProperty::Id(_) => PropertyType::Id,
IdProperty::Double(_) => PropertyType::Double,
IdProperty::IdArray(_) => PropertyType::IdArray,
}
}
pub fn name(&self) -> &str {
match self{
IdProperty::String(o) => o.name().unwrap(),
IdProperty::Int(o) => o.name().unwrap(),
IdProperty::Float(o) => o.name().unwrap(),
IdProperty::Array(o) => o.name().unwrap(),
IdProperty::Group(o) => o.name().unwrap(),
IdProperty::Id(o) => o.name().unwrap(),
IdProperty::Double(o) => o.name().unwrap(),
IdProperty::IdArray(o) => o.name().unwrap(),
}
}
pub fn value(&self) -> IdPropertyValue<'a>{
match self{
IdProperty::String(obj) => {
let subtype = *obj.get::<u8>("subtype").unwrap();
if subtype != 0 {
unimplemented!()
}
let len = *obj.get::<i32>("len").unwrap() as usize;
let value = obj.get_object("data")
.and_then(|d| d.get_data_slice::<u8>("pointer", len))
.and_then(|d| CStr::from_bytes_with_nul(d).map_err(|e| ::Error::from(format!("{}", e))))
.and_then(|s| s.to_str().map_err(|e| ::Error::from(format!("{}", e))))
.unwrap();
IdPropertyValue::String(value)
}
IdProperty::Int(obj) => {
let val = obj.get_object("data")
.and_then(|d| d.get::<i32>("val"))
.unwrap();
IdPropertyValue::Int(*val)
}
IdProperty::Float(obj) => {
let val = obj.get_object("data")
.and_then(|d| d.get::<f32>("val"))
.unwrap();
IdPropertyValue::Float(*val)
}
IdProperty::Double(obj) => {
let val = unsafe{ obj.get_object("data")
.and_then(|d| d.get_contiguous::<f64>("val"))
.unwrap() };
IdPropertyValue::Double(*val)
}
IdProperty::Group(obj) => {
let list = obj.get_object("data").and_then(|d| d.get_list("group")).unwrap();
IdPropertyValue::Group(Group{ list })
}
IdProperty::Array(obj) => {
let subtype = *obj.get::<PropertyType>("subtype").unwrap();
let len = *obj.get::<i32>("len").unwrap() as usize;
match subtype {
PropertyType::Int => {
let a = obj.get_object("data")
.and_then(|d| d.get_data_slice::<i32>("pointer", len))
.unwrap();
IdPropertyValue::ArrayInt(a)
}
PropertyType::Float => {
let a = obj.get_object("data")
.and_then(|d| d.get_data_slice::<f32>("pointer", len))
.unwrap();
IdPropertyValue::ArrayFloat(a)
}
PropertyType::Double => {
let a = obj.get_object("data")
.and_then(|d| d.get_data_slice::<f64>("pointer", len))
.unwrap();
IdPropertyValue::ArrayDouble(a)
}
_ => unimplemented!()
}
}
_ => IdPropertyValue::Id()
}
}
}
#[derive(Debug, Clone)]
pub enum IdPropertyValue<'a>{
String(&'a str),
Int(i32),
Float(f32),
ArrayInt(&'a [i32]),
ArrayFloat(&'a [f32]),
ArrayDouble(&'a [f64]),
Group(Group<'a>),
Id(),
Double(f64),
IdArray(),
}
#[derive(Clone)]
pub struct Group<'a>{
pub(crate) list: List<'a>
}
impl<'a> Group<'a>{
pub fn iter(&self) -> GroupIter<'a>{
GroupIter{
iter: self.list.iter()
}
}
}
impl<'a> Debug for Group<'a>{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.write_str("Group")
}
}
pub struct GroupIter<'a> {
pub(crate) iter: ListIter<'a>
}
impl<'a> Iterator for GroupIter<'a>{
type Item = IdProperty<'a>;
fn next(&mut self) -> Option<IdProperty<'a>>{
self.iter.next().and_then(|obj| IdProperty::new(obj).ok())
}
}
#[derive(Debug,Clone,Eq,PartialEq,Ord,PartialOrd,Hash)]
pub struct Error(pub String);
pub type Result<T> = result::Result<T,Error>;
impl convert::From<String> for Error{
fn from(msg: String) -> Error{
Error(msg)
}
}
impl Error {
pub fn msg(&self) -> String{
self.0.clone()
}
}
impl Display for Error{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result{
fmt.write_str(&self.0)
}
}
impl error::Error for Error{
fn description(&self) -> &str{
&self.0
}
}