Files
test-projects/rust/src/main.rs
T
2025-11-26 14:55:39 +01:00

116 lines
3.8 KiB
Rust

#![allow(dead_code, unused)]
use serde::{Deserialize, Serialize};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
for n in 0..16 {
let measurement: u16 = 65_535 / 16 * n;
let millikelvin = (((measurement as u32) * 21_875u32) >> 13) + 228_150u32;
let temperature = Temperature::from_millikelvin(millikelvin);
println!("raw = {measurement}, converted = {millikelvin}, temperature = {temperature}");
}
let measurement: u16 = 65_535;
let millikelvin = (((measurement as u32) * 21_875u32) >> 13) + 228_150u32;
let temperature = Temperature::from_millikelvin(millikelvin);
println!("raw = {measurement}, converted = {millikelvin}, temperature = {temperature}");
Ok(())
}
#[derive(Clone, Debug, thiserror::Error)]
pub enum TemperatureError {
#[error("provided input is invalid: {0}")]
InvalidInput(f32),
#[error("conversion between units changed the value noticeably")]
ConversionError,
}
/// type for temperature
/// represents the temperature in Millikelvin
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Temperature{
value: u32,
}
impl Temperature {
#[allow(non_upper_case_globals)]
const CELSIUS_OFFSET_C: f32 = 273.15f32;
/// create a new instance of `Temperature` from a value in Millikelvin
/// this function is an alias for `from_millikelvin()`
pub fn new(millikelvin: u32) -> Self {
Self::from_millikelvin(millikelvin)
}
/// create a new instance of `Temperature` from a value in Millikelvin
pub fn from_millikelvin(millikelvin: u32) -> Self {
Self { value: millikelvin }
}
/// create a new instance of `Temperature` from a value in degrees Celsius
pub fn from_celsius(celsius: f32) -> Result<Self, TemperatureError> {
if celsius < -Self::CELSIUS_OFFSET_C { return Err(TemperatureError::InvalidInput(celsius)) }
Ok(Self { value: Self::celsius_to_millikelvin(celsius)? })
}
/// returns the temperature value in Millikelvin
pub fn get_millikelvin(&self) -> u32 {
self.value
}
/// returns the temperature value in degrees celsius
pub fn get_celsius(&self) -> Result<f32, TemperatureError> {
Self::millikelvin_to_celsius(self.value)
}
fn celsius_to_millikelvin(celsius: f32) -> Result<u32, TemperatureError> {
const ACCEPTABLE_INACCURACY: f32 = 1.0 / 16.0;
let millikelvin: u32 = Self::celsius_to_millikelvin_unchecked(celsius);
let celsius_converted: f32 = Self::millikelvin_to_celsius_unchecked(millikelvin);
if f32::abs(celsius - celsius_converted) > ACCEPTABLE_INACCURACY {
return Err(TemperatureError::ConversionError);
}
Ok(millikelvin)
}
fn millikelvin_to_celsius(millikelvin: u32) -> Result<f32, TemperatureError> {
const ACCEPTABLE_INACCURACY: u32 = 80;
let celsius: f32 = Self::millikelvin_to_celsius_unchecked(millikelvin);
let millikelvin_converted: u32 = Self::celsius_to_millikelvin_unchecked(celsius);
if millikelvin.wrapping_sub(millikelvin_converted) > ACCEPTABLE_INACCURACY {
return Err(TemperatureError::ConversionError);
}
Ok(celsius)
}
fn celsius_to_millikelvin_unchecked(celsius: f32) -> u32 {
((celsius + Self::CELSIUS_OFFSET_C) * 1000.0) as u32
}
fn millikelvin_to_celsius_unchecked(millikelvin: u32) -> f32 {
let millicelsius: f32 = (millikelvin as f32) / 1000.0;
millicelsius - Self::CELSIUS_OFFSET_C
}
}
impl std::fmt::Display for Temperature {
// display `Temperatures` in degrees Celsius
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Ok(value) = Self::millikelvin_to_celsius(self.value) {
write!(f, "{:.2?}°C", value)?;
} else {
return Err(std::fmt::Error::default());
}
Ok(())
}
}