boring-parser 0.5.1

A Rust library for boring xml parsing
Documentation
/// 岩石群コード(全バージョン共通)
///
/// V1/V2: `Single` or `Interbedded` のみ(`Mixed` は構造上表現不可)
/// V3/V4: `Single`, `Interbedded`, `Mixed` の全3値
///
/// PDF仕様: V3.00 表2-13 / V4.00 表2-11
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RockGroupCode {
    /// 単一種の岩石(V3+: コード1)
    Single,
    /// 互層(V3+: コード2 / V1-V2: classification2が非空)
    Interbedded,
    /// 混在岩(V3+: コード3 / V1-V2: 表現不可)
    Mixed,
}

impl RockGroupCode {
    /// XML値("1", "2", "3")からenumに変換
    pub fn from_code(code: &str) -> Option<Self> {
        match code {
            "1" => Some(Self::Single),
            "2" => Some(Self::Interbedded),
            "3" => Some(Self::Mixed),
            _ => None,
        }
    }

    /// 互層かどうか
    pub fn is_interbedded(&self) -> bool {
        *self == Self::Interbedded
    }
}

/// 構成岩種の情報
///
/// V1.10〜V2.10 と V3.00+ でデータの性質が異なるためenumで分岐。
/// V1/V2は各構成岩種に個別の名前を持ち、V3+は9桁コードで識別する。
#[derive(Debug, Clone)]
pub enum Constituent {
    /// V1.10〜V2.10: 各構成岩種に個別の名前がある
    Named {
        /// 地質名称 / 土質岩種区分名(例: "シルト質砂")
        name: String,
        /// V1: 地質コード / V2: 土質岩種記号(例: "SM")
        symbol: Option<String>,
    },
    /// V3.00+: 構成岩種は9桁コードで識別(個別の名前なし)
    Coded {
        /// 堆積岩・火成岩の岩相コード
        lithofacies: Option<String>,
        /// 岩石コード
        rock: Option<String>,
        /// 変成岩の岩相コード
        metamorphic_rock_lithofacies: Option<String>,
        /// 変成岩の岩石コード
        metamorphic_rock: Option<String>,
    },
}

/// 岩石群情報(1つの岩石群 = コード + 構成岩種リスト)
#[derive(Debug, Clone)]
pub struct RockGroupInfo {
    pub code: RockGroupCode,
    pub constituents: Vec<Constituent>,
}

/// 地質分類の統一インターフェース
///
/// 各バージョンの地質分類構造体に実装し、バージョンを意識せず
/// 互層判定・構成岩種の取得を行えるようにする。
///
/// # Example
/// ```ignore
/// use boring_parser::classification::ClassificationInfo;
///
/// let groups = classification.rock_groups();
/// // 互層判定
/// if groups[0].code == RockGroupCode::Interbedded {
///     println!("互層: 構成岩種数 = {}", groups[0].constituents.len());
/// }
/// ```
pub trait ClassificationInfo {
    /// 岩石群のリストを返す。
    ///
    /// - V1/V2: 常に1要素(classification1/2から推定)
    /// - V3/V4: `rock_groups` の数だけ返す
    ///
    /// 互層判定: `groups[i].code == RockGroupCode::Interbedded`
    /// 構成岩種数: `groups[i].constituents.len()`
    fn rock_groups(&self) -> Vec<RockGroupInfo>;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_rock_group_code_from_code() {
        assert_eq!(RockGroupCode::from_code("1"), Some(RockGroupCode::Single));
        assert_eq!(
            RockGroupCode::from_code("2"),
            Some(RockGroupCode::Interbedded)
        );
        assert_eq!(RockGroupCode::from_code("3"), Some(RockGroupCode::Mixed));
        assert_eq!(RockGroupCode::from_code("4"), None);
        assert_eq!(RockGroupCode::from_code(""), None);
    }

    #[test]
    fn test_rock_group_code_is_interbedded() {
        assert!(!RockGroupCode::Single.is_interbedded());
        assert!(RockGroupCode::Interbedded.is_interbedded());
        assert!(!RockGroupCode::Mixed.is_interbedded());
    }
}