threemf 0.8.0

3MF (3D Manufacturing Format) file format support
Documentation
pub mod mesh;
pub use mesh::*;

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub struct Model {
    #[serde(rename = "@xmlns", default)]
    pub xmlns: String,
    #[serde(rename = "@xmlns:m", skip_serializing_if = "Option::is_none")]
    pub xmlns_m: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub metadata: Vec<Metadata>,
    pub resources: Resources,
    pub build: Build,
    #[serde(rename = "@unit", default)]
    pub unit: Unit,
}

/// Model measurement unit, default is millimeter
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Unit {
    Micron,
    Millimeter,
    Centimeter,
    Inch,
    Foot,
    Meter,
}

#[derive(Serialize, Deserialize)]
pub struct Metadata {
    #[serde(rename = "@name")]
    pub name: String,
    #[serde(rename = "$value")]
    pub value: Option<String>,
}

#[derive(Serialize, Deserialize, Default)]
pub struct Resources {
    #[serde(default)]
    pub object: Vec<Object>,
    #[serde(
        default,
        skip_serializing_if = "Option::is_none",
        rename = "m:basematerials"
    )]
    pub basematerials: Option<Vec<BaseMaterials>>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename = "m:basematerials")]
pub struct BaseMaterials {
    #[serde(rename = "@id")]
    pub id: usize,
    #[serde(rename = "m:base")]
    pub base: Vec<Base>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Base {
    #[serde(rename = "@name")]
    pub name: String,
    #[serde(rename = "@displaycolor")]
    pub displaycolor: String,
}

#[derive(Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub struct Object {
    #[serde(rename = "@id")]
    pub id: usize,
    #[serde(rename = "@partnumber", skip_serializing_if = "Option::is_none")]
    pub partnumber: Option<String>,
    #[serde(rename = "@name", skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(rename = "@pid", skip_serializing_if = "Option::is_none")]
    pub pid: Option<usize>,
    #[serde(rename = "@pindex", skip_serializing_if = "Option::is_none")]
    pub pindex: Option<usize>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub mesh: Option<Mesh>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub components: Option<Components>,
}

#[derive(Serialize, Deserialize)]
pub struct Components {
    pub component: Vec<Component>,
}

#[derive(Serialize, Deserialize)]
pub struct Component {
    #[serde(rename = "@objectid")]
    pub objectid: usize,
    #[serde(rename = "@transform", skip_serializing_if = "Option::is_none")]
    pub transform: Option<[f64; 12]>,
}
#[derive(Serialize, Deserialize, Default)]
pub struct Build {
    #[serde(default)]
    pub item: Vec<Item>,
}

#[derive(Serialize, Deserialize)]
pub struct Item {
    #[serde(rename = "@objectid")]
    pub objectid: usize,
    #[serde(rename = "@transform", skip_serializing_if = "Option::is_none")]
    pub transform: Option<[f64; 12]>,
    #[serde(rename = "@partnumber", skip_serializing_if = "Option::is_none")]
    pub partnumber: Option<String>,
}

impl Default for Model {
    fn default() -> Self {
        Self {
            xmlns: "http://schemas.microsoft.com/3dmanufacturing/core/2015/02".to_owned(),
            xmlns_m: Some(
                "http://schemas.microsoft.com/3dmanufacturing/material/2015/02".to_owned(),
            ),
            metadata: Vec::new(),
            resources: Resources::default(),
            build: Build::default(),
            unit: Unit::default(),
        }
    }
}

impl Default for Unit {
    fn default() -> Self {
        Self::Millimeter
    }
}

impl From<Mesh> for Model {
    fn from(mesh: Mesh) -> Self {
        let object = Object {
            id: 1,
            partnumber: None,
            name: None,
            pid: None,
            pindex: None,
            mesh: Some(mesh),
            components: None,
        };
        let resources = Resources {
            object: vec![object],
            basematerials: None,
        };
        let build = Build {
            item: vec![Item {
                objectid: 1,
                transform: None,
                partnumber: None,
            }],
        };
        Model {
            resources,
            build,
            ..Default::default()
        }
    }
}