Skip to main content

pdg_rs/models/
pdgdoc.rs

1use std::{fmt::Display, str::FromStr};
2
3use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ValueRef};
4
5use crate::PdgError;
6
7/// Classification for a PDG numeric value row.
8#[derive(Debug, Copy, Clone)]
9pub enum ValueType {
10    /// A weighted average value.
11    WeightedAverage,
12    /// The best limit selected by PDG.
13    BestLimit,
14    /// A branching ratio value.
15    BranchingRatio,
16    /// A PDG evaluation.
17    PdgEvaluation,
18    /// A PDG limit.
19    PdgLimit,
20    /// Extra material displayed below a value.
21    ExtraBelow,
22    /// Extra material displayed above a value.
23    ExtraAbove,
24    /// A fitted data value.
25    FittedData,
26    /// A fitted decay-rate value.
27    FittedDecayRate,
28    /// An estimated value.
29    Estimate,
30    /// A default evaluation value.
31    DefaultEvaluation,
32    /// An internal PDG value.
33    Internal,
34}
35
36impl ValueType {
37    /// Returns the compact PDG database code for this value type.
38    #[must_use]
39    pub const fn to_code(&self) -> &'static str {
40        match self {
41            Self::WeightedAverage => "AC",
42            Self::BestLimit => "L",
43            Self::BranchingRatio => "D",
44            Self::PdgEvaluation => "V",
45            Self::PdgLimit => "OL",
46            Self::ExtraBelow => "OM",
47            Self::ExtraAbove => "ON",
48            Self::FittedData => "FC",
49            Self::FittedDecayRate => "DR",
50            Self::Estimate => "E",
51            Self::DefaultEvaluation => "O",
52            Self::Internal => "DV",
53        }
54    }
55}
56
57impl Display for ValueType {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            "{}",
62            match self {
63                Self::WeightedAverage => "Weighted average",
64                Self::BestLimit => "Best limit",
65                Self::BranchingRatio => "Branching ratio",
66                Self::PdgEvaluation => "PDG evaluation",
67                Self::PdgLimit => "PDG limit",
68                Self::ExtraBelow => "Extra below",
69                Self::ExtraAbove => "Extra above",
70                Self::FittedData => "Fitted data",
71                Self::FittedDecayRate => "Fitted decay rate",
72                Self::Estimate => "Estimate",
73                Self::DefaultEvaluation => "Default evaluation",
74                Self::Internal => "Internal",
75            }
76        )
77    }
78}
79
80impl FromStr for ValueType {
81    type Err = PdgError;
82
83    fn from_str(s: &str) -> Result<Self, Self::Err> {
84        match s {
85            "AC" => Ok(Self::WeightedAverage),
86            "L" => Ok(Self::BestLimit),
87            "D" => Ok(Self::BranchingRatio),
88            "V" => Ok(Self::PdgEvaluation),
89            "OL" => Ok(Self::PdgLimit),
90            "OM" => Ok(Self::ExtraBelow),
91            "ON" => Ok(Self::ExtraAbove),
92            "FC" => Ok(Self::FittedData),
93            "DR" => Ok(Self::FittedDecayRate),
94            "E" => Ok(Self::Estimate),
95            "O" => Ok(Self::DefaultEvaluation),
96            "DV" => Ok(Self::Internal),
97            _ => Err(PdgError::ParseValueType(s.to_string())),
98        }
99    }
100}
101
102impl FromSql for ValueType {
103    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
104        match value {
105            ValueRef::Text(bytes) => {
106                let s =
107                    std::str::from_utf8(bytes).map_err(|err| FromSqlError::Other(Box::new(err)))?;
108                Self::from_str(s).map_err(|err| FromSqlError::Other(Box::new(err)))
109            }
110            _ => Err(FromSqlError::InvalidType),
111        }
112    }
113}
114
115/// Type of bound or range represented by a data value.
116#[derive(Debug, Copy, Clone, PartialEq, Eq)]
117pub enum LimitType {
118    /// An upper limit.
119    UpperLimit,
120    /// A lower limit.
121    LowerLimit,
122    /// A closed range.
123    Range,
124    /// An excluded range.
125    RangeExclusion,
126}
127
128impl LimitType {
129    /// Returns the compact PDG database code for this limit type.
130    #[must_use]
131    pub const fn to_code(&self) -> &'static str {
132        match self {
133            Self::UpperLimit => "U",
134            Self::LowerLimit => "L",
135            Self::Range => "R",
136            Self::RangeExclusion => "X",
137        }
138    }
139}
140
141impl Display for LimitType {
142    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143        write!(
144            f,
145            "{}",
146            match self {
147                Self::UpperLimit => "Upper limit",
148                Self::LowerLimit => "Lower limit",
149                Self::Range => "Range",
150                Self::RangeExclusion => "Range exclusion",
151            }
152        )
153    }
154}
155
156impl FromStr for LimitType {
157    type Err = PdgError;
158
159    fn from_str(s: &str) -> Result<Self, Self::Err> {
160        match s {
161            "U" => Ok(Self::UpperLimit),
162            "L" => Ok(Self::LowerLimit),
163            "R" => Ok(Self::Range),
164            "X" => Ok(Self::RangeExclusion),
165            _ => Err(PdgError::ParseLimitType(s.to_string())),
166        }
167    }
168}
169
170impl FromSql for LimitType {
171    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
172        match value {
173            ValueRef::Text(bytes) => {
174                let s =
175                    std::str::from_utf8(bytes).map_err(|err| FromSqlError::Other(Box::new(err)))?;
176                Self::from_str(s).map_err(|err| FromSqlError::Other(Box::new(err)))
177            }
178            _ => Err(FromSqlError::InvalidType),
179        }
180    }
181}
182
183/// Kind of data represented by a PDG identifier row.
184#[derive(Debug, Copy, Clone, PartialEq, Eq)]
185pub enum DataType {
186    /// Electric dipole moment data.
187    ElectricDipoleMoment,
188    /// Magnetic moment data.
189    MagneticMoment,
190    /// CP-violation parameter data.
191    CPViolationParameter,
192    /// Mass-difference data.
193    MassDifference,
194    /// Form-factor data.
195    FormFactor,
196    /// Mean-lifetime data.
197    MeanLifetime,
198    /// Slope-parameter data.
199    SlopeParameter,
200    /// Full-width data.
201    FullWidth,
202    /// Mass data.
203    Mass,
204    /// Coupling-constant ratio data.
205    CouplingConstantRatio,
206    /// Decay-parameter data.
207    DecayParameter,
208    /// Lifetime data.
209    Lifetime,
210    /// Exclusive branching-fraction data.
211    ExclusiveBranchingFraction,
212    /// Exclusive branching-fraction subtype 1.
213    ExclusiveBranchingFraction1,
214    /// Exclusive branching-fraction subtype 2.
215    ExclusiveBranchingFraction2,
216    /// Exclusive branching-fraction subtype 3.
217    ExclusiveBranchingFraction3,
218    /// Exclusive branching-fraction subtype 4.
219    ExclusiveBranchingFraction4,
220    /// Exclusive branching-fraction subtype 5.
221    ExclusiveBranchingFraction5,
222    /// Inclusive branching-fraction data.
223    InclusiveBranchingFraction,
224    /// Inclusive branching-fraction subtype 1.
225    InclusiveBranchingFraction1,
226    /// Inclusive branching-fraction subtype 2.
227    InclusiveBranchingFraction2,
228    /// Inclusive branching-fraction subtype 3.
229    InclusiveBranchingFraction3,
230    /// Inclusive branching-fraction subtype 4.
231    InclusiveBranchingFraction4,
232    /// Inclusive branching-fraction subtype 5.
233    InclusiveBranchingFraction5,
234    /// Branching-ratio data.
235    BranchingRatio,
236    /// Particle identity row.
237    Particle,
238    /// Search-result or search-summary row.
239    Searches,
240    /// Section heading row.
241    Section,
242    /// Unknown or unclassified data.
243    Other,
244}
245
246impl FromSql for DataType {
247    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
248        match value {
249            ValueRef::Text(bytes) => {
250                let s =
251                    std::str::from_utf8(bytes).map_err(|err| FromSqlError::Other(Box::new(err)))?;
252                Self::from_str(s).map_err(|err| FromSqlError::Other(Box::new(err)))
253            }
254            _ => Err(FromSqlError::InvalidType),
255        }
256    }
257}
258
259impl DataType {
260    /// Returns the compact PDG database code for this data type.
261    #[must_use]
262    pub const fn to_code(&self) -> &'static str {
263        match self {
264            Self::ElectricDipoleMoment => "e",
265            Self::MagneticMoment => "m",
266            Self::CPViolationParameter => "v",
267            Self::MassDifference => "D",
268            Self::FormFactor => "f",
269            Self::MeanLifetime => "g",
270            Self::SlopeParameter => "s",
271            Self::FullWidth => "G",
272            Self::Mass => "M",
273            Self::CouplingConstantRatio => "c",
274            Self::DecayParameter => "d",
275            Self::Lifetime => "T",
276            Self::ExclusiveBranchingFraction => "BFX",
277            Self::ExclusiveBranchingFraction1 => "BFX1",
278            Self::ExclusiveBranchingFraction2 => "BFX2",
279            Self::ExclusiveBranchingFraction3 => "BFX3",
280            Self::ExclusiveBranchingFraction4 => "BFX4",
281            Self::ExclusiveBranchingFraction5 => "BFX5",
282            Self::InclusiveBranchingFraction => "BFI",
283            Self::InclusiveBranchingFraction1 => "BFI1",
284            Self::InclusiveBranchingFraction2 => "BFI2",
285            Self::InclusiveBranchingFraction3 => "BFI3",
286            Self::InclusiveBranchingFraction4 => "BFI4",
287            Self::InclusiveBranchingFraction5 => "BFI5",
288            Self::BranchingRatio => "BR",
289            Self::Particle => "PART",
290            Self::Searches => "SRCH",
291            Self::Section => "SEC",
292            Self::Other => "",
293        }
294    }
295
296    /// Returns `true` for inclusive and exclusive branching-fraction data types.
297    #[must_use]
298    pub const fn is_branching_fraction(&self) -> bool {
299        matches!(
300            self,
301            Self::ExclusiveBranchingFraction
302                | Self::ExclusiveBranchingFraction1
303                | Self::ExclusiveBranchingFraction2
304                | Self::ExclusiveBranchingFraction3
305                | Self::ExclusiveBranchingFraction4
306                | Self::ExclusiveBranchingFraction5
307                | Self::InclusiveBranchingFraction
308                | Self::InclusiveBranchingFraction1
309                | Self::InclusiveBranchingFraction2
310                | Self::InclusiveBranchingFraction3
311                | Self::InclusiveBranchingFraction4
312                | Self::InclusiveBranchingFraction5
313        )
314    }
315
316    /// Returns `true` for particle-level properties such as mass, width, and lifetime.
317    #[must_use]
318    pub const fn is_particle_property(&self) -> bool {
319        !matches!(
320            self,
321            Self::BranchingRatio | Self::Particle | Self::Searches | Self::Section | Self::Other
322        ) && !self.is_branching_fraction()
323    }
324}
325
326impl Display for DataType {
327    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
328        write!(
329            f,
330            "{}",
331            match self {
332                Self::ElectricDipoleMoment => "Electric dipole moment",
333                Self::MagneticMoment => "Magnetic moment",
334                Self::CPViolationParameter => "CP violation parameter",
335                Self::MassDifference => "Mass difference",
336                Self::FormFactor => "Form factor",
337                Self::MeanLifetime => "Mean lifetime",
338                Self::SlopeParameter => "Slope parameter",
339                Self::FullWidth => "Width",
340                Self::Mass => "Mass",
341                Self::CouplingConstantRatio => "Coupling constant ratio",
342                Self::DecayParameter => "Decay parameter",
343                Self::Lifetime => "Lifetime",
344                Self::ExclusiveBranchingFraction
345                | Self::ExclusiveBranchingFraction1
346                | Self::ExclusiveBranchingFraction2
347                | Self::ExclusiveBranchingFraction3
348                | Self::ExclusiveBranchingFraction4
349                | Self::ExclusiveBranchingFraction5 => "Exclusive branching fraction",
350                Self::InclusiveBranchingFraction
351                | Self::InclusiveBranchingFraction1
352                | Self::InclusiveBranchingFraction2
353                | Self::InclusiveBranchingFraction3
354                | Self::InclusiveBranchingFraction4
355                | Self::InclusiveBranchingFraction5 => "Inclusive branching fraction",
356                Self::BranchingRatio => "Branching ratio",
357                Self::Particle => "Particle",
358                Self::Searches => "Searches",
359                Self::Section => "Section",
360                Self::Other => "Other",
361            }
362        )
363    }
364}
365
366impl FromStr for DataType {
367    type Err = PdgError;
368
369    fn from_str(s: &str) -> Result<Self, Self::Err> {
370        match s {
371            "e" => Ok(Self::ElectricDipoleMoment),
372            "m" => Ok(Self::MagneticMoment),
373            "v" => Ok(Self::CPViolationParameter),
374            "D" => Ok(Self::MassDifference),
375            "f" => Ok(Self::FormFactor),
376            "g" => Ok(Self::MeanLifetime),
377            "s" => Ok(Self::SlopeParameter),
378            "G" => Ok(Self::FullWidth),
379            "M" => Ok(Self::Mass),
380            "c" => Ok(Self::CouplingConstantRatio),
381            "d" => Ok(Self::DecayParameter),
382            "T" => Ok(Self::Lifetime),
383            "BFX" => Ok(Self::ExclusiveBranchingFraction),
384            "BFX1" => Ok(Self::ExclusiveBranchingFraction1),
385            "BFX2" => Ok(Self::ExclusiveBranchingFraction2),
386            "BFX3" => Ok(Self::ExclusiveBranchingFraction3),
387            "BFX4" => Ok(Self::ExclusiveBranchingFraction4),
388            "BFX5" => Ok(Self::ExclusiveBranchingFraction5),
389            "BFI" => Ok(Self::InclusiveBranchingFraction),
390            "BFI1" => Ok(Self::InclusiveBranchingFraction1),
391            "BFI2" => Ok(Self::InclusiveBranchingFraction2),
392            "BFI3" => Ok(Self::InclusiveBranchingFraction3),
393            "BFI4" => Ok(Self::InclusiveBranchingFraction4),
394            "BFI5" => Ok(Self::InclusiveBranchingFraction5),
395            "BR" => Ok(Self::BranchingRatio),
396            "PART" => Ok(Self::Particle),
397            "SRCH" => Ok(Self::Searches),
398            "SEC" => Ok(Self::Section),
399            "" => Ok(Self::Other),
400            _ => Err(PdgError::ParseDataType(s.to_string())),
401        }
402    }
403}