dmio 0.1.2

A shared library providing functionality to read, write and modify files saved in the DigitalMicrograph file format (version 3 or 4)
Documentation
/*
 * Copyright 2018 Christian Ebner
 *
 * This file is part of dmio.
 *
 * dmio is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * dmio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with dmio.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::default::Default;
use std::collections::BTreeMap;
use std::collections::btree_map::{Iter, IterMut};
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::fmt;

use self::Key::*;
use self::Tag::*;

/// The enum Key is used as key for the TagGroup entries in a BTreeMap.
/// As key, generally the label of the TagGroup entry is used.
/// Since some TagGroup entries do not provide a label, in that case an Index is used.
#[derive(Debug, Clone, Eq)]
pub enum Key {
    Label(String),
    Index(usize),
}

impl PartialEq for Key {
    fn eq(&self, other: &Key) -> bool {
        match (self, other) {
            (&Label(ref label), &Label(ref other_label)) => label == other_label,
            (&Index(index), &Index(other_index)) => index == other_index,
            (&Index(_), &Label(_)) |
            (&Label(_), &Index(_)) => false,
        }
    }
}

impl PartialOrd for Key {
    fn partial_cmp(&self, other: &Key) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Key {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self, other) {
            (&Label(ref label), &Label(ref other_label)) => label.cmp(other_label),
            (&Label(_), &Index(_)) => Ordering::Greater,
            (&Index(index), &Index(other_index)) => index.cmp(&other_index),
            (&Index(_), &Label(_)) => Ordering::Less,
        }
    }
}

impl Key {
    #[inline]
    pub fn from_str(key: &str) -> Key {
        Label(key.to_string())
    }

    #[inline]
    pub fn from_usize(key: usize) -> Key {
        Index(key)
    }
}

impl fmt::Display for Key {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Label(ref l) => write!(f, "Key({})", l),
            Index(ref i) => write!(f, "Key({})", i),
        }
    }
}

/// Tag is an enum defining which type the TagGroup entry has and
/// allowing abstraction over TagGroup entries.
#[derive(Debug)]
pub enum Tag {
    Empty,
    Short(i16),
    Long(i32),
    UShort(u16),
    ULong(u32),
    Float(f32),
    Double(f64),
    Boolean(bool),
    Char(char),
    Octet(u8),
    ULongLong(u64),
    Unknown64(u64),
    CharSeq(String),
    ArrayShort(Vec<i16>),
    ArrayLong(Vec<i32>),
    ArrayUShort(Vec<u16>),
    ArrayULong(Vec<u32>),
    ArrayFloat(Vec<f32>),
    ArrayDouble(Vec<f64>),
    ArrayBoolean(Vec<bool>),
    ArrayChar(String),
    ArrayOctet(Vec<u8>),
    ArrayULongLong(Vec<u64>),
    ArrayUnknown64(Vec<u64>),
    Struct(Vec<Tag>),
    ComplexArray(Vec<Tag>),
    TagGroupEntry(TagGroup),
}

impl Default for Tag {
    fn default() -> Self {
        Empty
    }
}

impl Tag {
    #[inline]
    pub fn get(&self, key: &str) -> Option<&Tag> {
        let k = Key::from_str(key);
        self.get_tag(&k)
    }

    #[inline]
    pub fn get_mut(&mut self, key: &str) -> Option<&mut Tag> {
        let k = Key::from_str(key);
        self.get_tag_mut(&k)
    }

    #[inline]
    pub fn get_tag(&self, key: &Key) -> Option<&Tag> {
        match *self {
            TagGroupEntry(ref tg) => tg.get_tag(key),
            _ => None,
        }
    }

    #[inline]
    pub fn get_tag_mut(&mut self, key: &Key) -> Option<&mut Tag> {
        match *self {
            TagGroupEntry(ref mut tg) => tg.get_tag_mut(key),
            _ => None,
        }
    }
}

#[derive(Debug)]
pub struct TagGroup {
    data: BTreeMap<Key, Tag>,
    is_sorted: bool,
    is_open: bool,
}

impl Default for TagGroup {
    fn default() -> Self {
        TagGroup {
            data: BTreeMap::new(),
            is_sorted: true,
            is_open: false,
        }
    }
}

impl TagGroup {
    #[inline]
    pub fn new(is_sorted: bool, is_open: bool) -> Self {
        TagGroup {
            data: BTreeMap::new(),
            is_sorted,
            is_open,
        }
    }

    #[inline]
    pub fn sorted(&self) -> bool {
        self.is_sorted
    }

    #[inline]
    pub fn opened(&self) -> bool {
        self.is_open
    }

    /// Returns the number of entries of the TagGroup
    #[inline]
    pub fn len(&self) -> usize {
        self.data.len()
    }

    #[inline]
    pub fn get(&self, key: &str) -> Option<&Tag> {
        let k = Key::from_str(key);
        self.data.get(&k)
    }

    #[inline]
    pub fn get_mut(&mut self, key: &str) -> Option<&mut Tag> {
        let k = Key::from_str(key);
        self.data.get_mut(&k)
    }

    #[inline]
    pub fn get_tag(&self, key: &Key) -> Option<&Tag> {
        self.data.get(key)
    }

    #[inline]
    pub fn get_tag_mut(&mut self, key: &Key) -> Option<&mut Tag> {
        self.data.get_mut(key)
    }

    #[inline]
    pub fn insert(&mut self, key: Key, tag: Tag) -> Option<Tag> {
        self.data.insert(key, tag)
    }

    pub fn iter(&self) -> Iter<Key, Tag> {
        self.data.iter()
    }

    #[inline]
    pub fn iter_mut(&mut self) -> IterMut<Key, Tag> {
        self.data.iter_mut()
    }
}