use super::{ConstantInitLink, ParsedLink, Record, parse_link_v2};
use crate::types::{DbFieldType, EpicsValue, PvString};
fn constant_to_field_type(value: EpicsValue, target: DbFieldType, raw: &str) -> EpicsValue {
use DbFieldType as T;
if target == T::String {
return EpicsValue::String(PvString::from(raw));
}
let integral = matches!(
target,
T::Char
| T::UChar
| T::Short
| T::UShort
| T::Enum
| T::Long
| T::ULong
| T::Int64
| T::UInt64
);
if integral {
if let Some(v) = value.to_f64() {
if v.is_finite() {
return EpicsValue::Int64(v.trunc() as i64).convert_to(target);
}
}
}
value.convert_to(target)
}
pub fn rec_gbl_init_constant_link<R: Record + ?Sized>(
record: &mut R,
seed: &ConstantInitLink,
) -> Option<EpicsValue> {
let Some(EpicsValue::String(link_str)) = record.get_field(seed.link_field) else {
return None;
};
let parsed = parse_link_v2(link_str.as_str_lossy().as_ref());
let ParsedLink::Constant(raw) = &parsed else {
return None;
};
let raw = raw.clone();
let value = crate::server::recgbl::simm::constant_load_value(&parsed)?;
let target_type = super::record_instance::declared_field_type_of(record, seed.target_field)
.or_else(|| {
record
.get_field(seed.target_field)
.map(|v| v.db_field_type())
});
let value = match target_type {
Some(t) => constant_to_field_type(value, t, &raw),
None => value,
};
let value = if seed.normalize_bool {
EpicsValue::Enum(u16::from(value.to_f64().is_some_and(|v| v != 0.0)))
} else {
value
};
record.put_field(seed.target_field, value.clone()).ok()?;
Some(value)
}
pub fn reseed_constant_input_link<R: Record + ?Sized>(
record: &mut R,
link_field: &str,
) -> Option<&'static str> {
let seed = record
.special_reseed_input_links()
.iter()
.find(|(link, _)| *link == link_field)
.map(|(link, target)| ConstantInitLink::new(link, target))?;
rec_gbl_init_constant_link(record, &seed).map(|_| seed.target_field)
}