utodo 2.0.1

A universal TODO list format.
Documentation
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};

pub const UTODO_VERSION: &str = clap::crate_version!();

#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields, default))]
/// Todo list struct
pub struct TodoList {
    pub utodo: (u32, u32, u32),
    pub pending: TodoListItems,
    pub progress: TodoListItems,
    pub finished: TodoListItems,
}

impl TodoList {
    pub fn default() -> Self {
        return Self {
            utodo: utodo_version(),
            pending: TodoListItems::default(),
            progress: TodoListItems::default(),
            finished: TodoListItems::default(),
        };
    }

    #[cfg(feature = "toml")]
    pub fn to_toml_string(&self) -> String {
        return toml::to_string_pretty(self).unwrap();
    }

    #[cfg(feature = "toml")]
    pub fn from_toml_str(input: &str) -> Result<Self, toml::de::Error> {
        return toml::from_str(input);
    }

    /// Convert to 3 list arrays (pending, progress, finished)
    pub fn to_lists(self) -> [Vec<String>; 3] {
        return [
            self.pending.items,
            self.progress.items,
            self.finished.items,
        ];
    }

    /// Get TodoList from 3 list arrays (pending, progress, finished)
    /// Can be serialized and deserialized with the utodo/full feature
    pub fn from_lists(pending: &[String], progress: &[String], finished: &[String]) -> Self {
        let pending_list = TodoListItems { items: pending.to_vec() };
        let progress_list = TodoListItems { items: progress.to_vec() };
        let finished_list = TodoListItems { items: finished.to_vec() };
    
        let mut todo = Self::default();
    
        todo.pending = pending_list;
        todo.progress = progress_list;
        todo.finished = finished_list;
    
        return todo;
    }
}

#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields, default))]
pub struct TodoListItems {
    pub items: Vec<String>,
}

impl TodoListItems {
    pub fn default() -> Self {
        return Self {
            items: Vec::new(),
        };
    }
}

/// Get the UTodo version as a tuple of (u32, u32, u32) ((1, 1, 2) -> 1.1.2)
pub fn utodo_version() -> (u32, u32, u32) {
    let mut result: (u32, u32, u32) = (0, 0, 0);

    let version_vec: Vec<u32> = UTODO_VERSION.split(".")
        .map(|x| x.trim()
            .parse()
            .unwrap()
        ).collect();

    assert!(version_vec.len() == 3);

    result.0 = version_vec[0];
    result.1 = version_vec[1];
    result.2 = version_vec[2];

    return result;
}

#[test]
fn test() {
    let version = utodo_version();

    assert!(format!("{}.{}.{}", version.0, version.1, version.2) == UTODO_VERSION);

    let pending = vec![
        "Make a cup of tea.".into(),
        "Make breakfast.".into(),
    ];

    let progress = vec![
        "Wait for dad to get back with the milk.".into(),
    ];

    let finished = vec![
        "Feed the ducks.".into(),
    ];

    let as_struct = TodoList::from_lists(&pending, &progress, &finished);

    assert!(as_struct.pending.items == pending);
    assert!(as_struct.progress.items == progress);
    assert!(as_struct.finished.items == finished);
}