Skip to main content

pdg_rs/models/
pdgdata.rs

1use std::fmt::Display;
2
3use rusqlite::Row;
4
5use crate::{LimitType, Pdg, PdgFootnote, PdgId, PdgMeasurement, PdgResult, PdgText, ValueType};
6
7/// Numeric data row for a PDG identifier.
8///
9/// Data entries retain a link to the originating [`Pdg`](crate::Pdg) handle so
10/// related measurements, footnotes, and text blocks can be loaded on demand.
11#[derive(Clone, Debug)]
12pub struct DataEntry<'pdg> {
13    pub(crate) db: &'pdg Pdg,
14    /// PDG identifier for this data row.
15    pub pdgid: PdgId,
16    /// PDG edition for this value.
17    pub edition: String,
18    /// Classification of the value row.
19    pub value_type: ValueType,
20    /// Whether the row appears in the PDG summary table.
21    pub in_summary_table: bool,
22    /// Confidence level associated with the row.
23    pub confidence_level: Option<f64>,
24    /// Limit or range type, when this row is not a simple central value.
25    pub limit_type: Option<LimitType>,
26    /// PDG comment attached to the data row.
27    pub comment: Option<String>,
28    /// Parsed numeric central value.
29    pub value: Option<f64>,
30    /// Raw value text when the value is not represented solely by [`DataEntry::value`].
31    pub value_text: Option<String>,
32    /// Positive uncertainty on [`DataEntry::value`].
33    pub error_positive: Option<f64>,
34    /// Negative uncertainty on [`DataEntry::value`].
35    pub error_negative: Option<f64>,
36    /// PDG scale factor applied to this value.
37    pub scale_factor: Option<f64>,
38    /// Unit text from the PDG table.
39    pub unit_text: String,
40    /// Display-ready value text from the PDG table.
41    pub display_value_text: String,
42    /// Power-of-ten exponent used when displaying the value.
43    pub display_power_of_ten: isize,
44    /// Whether the display value should be interpreted as a percentage.
45    pub display_in_percent: bool,
46    /// Sort key used by the PDG tables.
47    pub sort: Option<isize>,
48}
49
50impl DataEntry<'_> {
51    pub(crate) const COLUMNS: &'static str = "pdgdata.pdgid, edition, value_type, in_summary_table, confidence_level, limit_type, comment, value, value_text, error_positive, error_negative, scale_factor, unit_text, display_value_text, display_power_of_ten, display_in_percent, pdgdata.sort";
52    pub(crate) const COLUMN_COUNT: usize = 17;
53}
54
55impl<'pdg> DataEntry<'pdg> {
56    pub(crate) fn from_row(db: &'pdg Pdg, row: &Row<'_>) -> rusqlite::Result<Self> {
57        Ok(Self {
58            db,
59            pdgid: row.get(0)?,
60            edition: row.get(1)?,
61            value_type: row.get(2)?,
62            in_summary_table: row.get(3)?,
63            confidence_level: row.get(4)?,
64            limit_type: row.get(5)?,
65            comment: row.get(6)?,
66            value: row.get(7)?,
67            value_text: row.get(8)?,
68            error_positive: row.get(9)?,
69            error_negative: row.get(10)?,
70            scale_factor: row.get(11)?,
71            unit_text: row.get(12)?,
72            display_value_text: row.get(13)?,
73            display_power_of_ten: row.get(14)?,
74            display_in_percent: row.get(15)?,
75            sort: row.get(16)?,
76        })
77    }
78
79    /// Loads measurements supporting this data entry.
80    ///
81    /// # Errors
82    ///
83    /// Returns a database error if the measurement query cannot be executed.
84    pub fn measurements(&self) -> PdgResult<Vec<PdgMeasurement>> {
85        self.db.measurements_for(&self.pdgid)
86    }
87
88    /// Loads footnotes attached to this data entry.
89    ///
90    /// # Errors
91    ///
92    /// Returns a database error if the footnote query cannot be executed.
93    pub fn footnotes(&self) -> PdgResult<Vec<PdgFootnote>> {
94        self.db.footnotes_for(&self.pdgid)
95    }
96
97    /// Loads text blocks attached to this data entry.
98    ///
99    /// # Errors
100    ///
101    /// Returns a database error if the text query cannot be executed.
102    pub fn texts(&self) -> PdgResult<Vec<PdgText>> {
103        self.db.texts_for(&self.pdgid)
104    }
105}
106
107impl Display for DataEntry<'_> {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        write!(f, "{}", self.display_value_text)?;
110        if self.display_in_percent {
111            write!(f, "%")?;
112        } else if self.display_power_of_ten != 0 {
113            write!(f, "E{}", self.display_power_of_ten)?;
114        }
115        if !self.unit_text.is_empty() {
116            write!(f, " {}", self.unit_text)?;
117        }
118        Ok(())
119    }
120}