use std::cell::UnsafeCell;
use std::fmt;
use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
struct F64Visitor;
impl<'de> Visitor<'de> for F64Visitor {
type Value = f64;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a float")
}
fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(f64::from(value))
}
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(value)
}
}
#[derive(Debug)]
pub struct SharedValue {
value: UnsafeCell<f64>,
}
impl Serialize for SharedValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_f64(self.get_value())
}
}
impl<'de> Deserialize<'de> for SharedValue {
fn deserialize<D>(deserializer: D) -> Result<SharedValue, D::Error>
where
D: Deserializer<'de>,
{
deserializer
.deserialize_f64(F64Visitor)
.map(SharedValue::new)
}
}
unsafe impl Send for SharedValue {}
unsafe impl Sync for SharedValue {}
impl SharedValue {
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn new(val: f64) -> SharedValue {
SharedValue {
value: UnsafeCell::new(val),
}
}
pub fn get_value(&self) -> f64 {
unsafe { *self.value.get() }
}
pub fn set_value(&self, value: f64) {
unsafe {
self.value.get().write(value);
}
}
}
#[cfg(test)]
mod shared_value_tests {
#![allow(clippy::float_cmp)]
use approx::assert_abs_diff_eq;
use super::*;
#[test]
fn new() {
let x = 1.;
let value = SharedValue::new(x);
assert_eq!(value.get_value(), 1.);
}
#[test]
fn set_value() {
let value = SharedValue::new(1.);
assert_abs_diff_eq!(value.get_value(), 1.);
value.set_value(0.5);
assert_eq!(value.get_value(), 0.5);
}
#[test]
fn set_value_var() {
let value = SharedValue::new(1.);
assert_eq!(value.get_value(), 1.);
assert_eq!(value.get_value(), 1.);
value.set_value(0.5);
assert_eq!(value.get_value(), 0.5);
}
#[test]
fn pointers() {
let value1 = SharedValue::new(1.);
let value2 = &value1;
assert_eq!(value1.get_value(), 1.);
assert_eq!(value2.get_value(), 1.);
value2.set_value(0.5);
assert_eq!(value1.get_value(), 0.5);
assert_eq!(value2.get_value(), 0.5);
}
#[test]
fn clone_var() {
let value1 = SharedValue::new(1.0);
let value2 = &value1;
assert_eq!(value1.get_value(), 1.0);
assert_eq!(value2.get_value(), 1.0);
value1.set_value(0.);
assert_eq!(value1.get_value(), 0.);
assert_eq!(value2.get_value(), 0.);
value2.set_value(0.5);
assert_eq!(value1.get_value(), 0.5);
assert_eq!(value2.get_value(), 0.5);
}
}