use std::cmp::Ordering;
use crate::attribute::Attribute;
use crate::context::{Context, Ptr};
use crate::result::Result;
use crate::r#type::TypeObj;
use crate::utils::apfloat::{Category, DynFloat, ExpInt, Round, Semantics, StatusAnd};
use pliron::derive::attr_interface;
#[attr_interface]
pub trait TypedAttrInterface {
fn get_type(&self, ctx: &Context) -> Ptr<TypeObj>;
fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
where
Self: Sized,
{
Ok(())
}
}
#[attr_interface]
pub trait OutlinedAttr {
fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
where
Self: Sized,
{
Ok(())
}
}
#[attr_interface]
pub trait PrintOnceAttr: OutlinedAttr {
fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
where
Self: Sized,
{
Ok(())
}
}
#[attr_interface]
pub trait FloatAttr: TypedAttrInterface {
fn get_inner(&self) -> &dyn DynFloat;
fn build_from(&self, df: Box<dyn DynFloat>) -> Box<dyn FloatAttr>;
fn get_semantics(&self) -> Semantics;
fn get_semantics_static() -> Semantics
where
Self: Sized;
fn build_qnan(&self, payload: Option<u128>) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let qnan = df.build_qnan(payload);
self.build_from(qnan)
}
fn build_snan(&self, payload: Option<u128>) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let snan = df.build_snan(payload);
self.build_from(snan)
}
fn build_largest(&self) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let largest = df.build_largest();
self.build_from(largest)
}
fn build_smallest_normalized(&self) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let smallest_normalized = df.build_smallest_normalized();
self.build_from(smallest_normalized)
}
fn build_from_bits(&self, bits: u128) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let from_bits = df.build_from_bits(bits);
self.build_from(from_bits)
}
fn build_from_u128_r(&self, value: u128, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.build_from_u128_r(value, round)
.map(|df| self.build_from(df))
}
fn build_from_str_r(&self, s: &str, round: Round) -> Result<StatusAnd<Box<dyn FloatAttr>>> {
let df = self.get_inner();
let res = df.build_from_str_r(s, round)?;
Ok(res.map(|df| self.build_from(df)))
}
fn build_from_i128_r(&self, value: i128, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.build_from_i128_r(value, round)
.map(|from_i128_r| self.build_from(from_i128_r))
}
fn build_from_i128(&self, value: i128) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.build_from_i128(value)
.map(|from_i128| self.build_from(from_i128))
}
fn build_from_u128(&self, value: u128) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.build_from_u128(value)
.map(|from_u128| self.build_from(from_u128))
}
fn neg(&self) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let negated = df.neg();
self.build_from(negated)
}
fn add(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.add(rhs_df).map(|add| self.build_from(add))
}
fn sub(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.sub(rhs_df).map(|sub| self.build_from(sub))
}
fn mul(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.mul(rhs_df).map(|mul| self.build_from(mul))
}
fn div(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.div(rhs_df).map(|div| self.build_from(div))
}
fn rem(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.rem(rhs_df).map(|rem| self.build_from(rem))
}
fn add_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.add_r(rhs_df, round).map(|add_r| self.build_from(add_r))
}
fn mul_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.mul_r(rhs_df, round).map(|mul_r| self.build_from(mul_r))
}
fn mul_add_r(
&self,
rhs: &dyn FloatAttr,
addend: &dyn FloatAttr,
round: Round,
) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
let addend_df = addend.get_inner();
df.mul_add_r(rhs_df, addend_df, round)
.map(|mul_add_r| self.build_from(mul_add_r))
}
fn div_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.div_r(rhs_df, round).map(|div_r| self.build_from(div_r))
}
fn ieee_rem(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.ieee_rem(rhs_df)
.map(|ieee_rem| self.build_from(ieee_rem))
}
fn c_fmod(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.c_fmod(rhs_df).map(|c_fmod| self.build_from(c_fmod))
}
fn round_to_integral(&self, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.round_to_integral(round)
.map(|round_to_integral| self.build_from(round_to_integral))
}
fn next_up(&self) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.next_up().map(|next_up| self.build_from(next_up))
}
fn to_bits(&self) -> u128 {
let df = self.get_inner();
df.to_bits()
}
fn to_u128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
let df = self.get_inner();
df.to_u128_r(width, round, is_exact)
}
fn cmp_abs_normal(&self, other: &dyn FloatAttr) -> Ordering {
let df = self.get_inner();
df.cmp_abs_normal(other.get_inner())
}
fn bitwise_eq(&self, other: &dyn FloatAttr) -> bool {
let df = self.get_inner();
df.bitwise_eq(other.get_inner())
}
fn is_negative(&self) -> bool {
let df = self.get_inner();
df.is_negative()
}
fn is_denormal(&self) -> bool {
let df = self.get_inner();
df.is_denormal()
}
fn is_signaling(&self) -> bool {
let df = self.get_inner();
df.is_signaling()
}
fn category(&self) -> Category {
let df = self.get_inner();
df.category()
}
fn get_exact_inverse(&self) -> Option<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.get_exact_inverse()
.map(|inverse| self.build_from(inverse))
}
fn ilogb(&self) -> ExpInt {
let df = self.get_inner();
df.ilogb()
}
fn scalbn_r(&self, n: ExpInt, round: Round) -> Box<dyn FloatAttr> {
let df = self.get_inner();
self.build_from(df.scalbn_r(n, round))
}
fn frexp_r(&self, exp: &mut ExpInt, round: Round) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let frexp_r = df.frexp_r(exp, round);
self.build_from(frexp_r)
}
fn sub_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let rhs_df = rhs.get_inner();
df.sub_r(rhs_df, round).map(|sub_r| self.build_from(sub_r))
}
fn mul_add(
&self,
multiplicand: &dyn FloatAttr,
addend: &dyn FloatAttr,
) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
let multiplicand_df = multiplicand.get_inner();
let addend_df = addend.get_inner();
df.mul_add(multiplicand_df, addend_df)
.map(|mul_add| self.build_from(mul_add))
}
fn next_down(&self) -> StatusAnd<Box<dyn FloatAttr>> {
let df = self.get_inner();
df.next_down().map(|next_down| self.build_from(next_down))
}
fn abs(&self) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let abs = df.abs();
self.build_from(abs)
}
fn copy_sign(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let other_df = other.get_inner();
self.build_from(df.copy_sign(other_df))
}
fn to_i128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> {
let df = self.get_inner();
df.to_i128_r(width, round, is_exact)
}
fn to_i128(&self, width: usize) -> StatusAnd<i128> {
let df = self.get_inner();
df.to_i128(width)
}
fn to_u128(&self, width: usize) -> StatusAnd<u128> {
let df = self.get_inner();
df.to_u128(width)
}
fn min(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let other_df = other.get_inner();
self.build_from(df.min(other_df))
}
fn max(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let other_df = other.get_inner();
self.build_from(df.max(other_df))
}
fn minimum(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let other_df = other.get_inner();
self.build_from(df.minimum(other_df))
}
fn maximum(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let other_df = other.get_inner();
self.build_from(df.maximum(other_df))
}
fn is_normal(&self) -> bool {
let df = self.get_inner();
df.is_normal()
}
fn is_finite(&self) -> bool {
let df = self.get_inner();
df.is_finite()
}
fn is_zero(&self) -> bool {
let df = self.get_inner();
df.is_zero()
}
fn is_infinite(&self) -> bool {
let df = self.get_inner();
df.is_infinite()
}
fn is_nan(&self) -> bool {
let df = self.get_inner();
df.is_nan()
}
fn is_non_zero(&self) -> bool {
let df = self.get_inner();
df.is_non_zero()
}
fn is_finite_non_zero(&self) -> bool {
let df = self.get_inner();
df.is_finite_non_zero()
}
fn is_pos_zero(&self) -> bool {
let df = self.get_inner();
df.is_pos_zero()
}
fn is_neg_zero(&self) -> bool {
let df = self.get_inner();
df.is_neg_zero()
}
fn is_pos_infinity(&self) -> bool {
let df = self.get_inner();
df.is_pos_infinity()
}
fn is_neg_infinity(&self) -> bool {
let df = self.get_inner();
df.is_neg_infinity()
}
fn is_smallest(&self) -> bool {
let df = self.get_inner();
df.is_smallest()
}
fn is_smallest_normalized(&self) -> bool {
let df = self.get_inner();
df.is_smallest_normalized()
}
fn is_largest(&self) -> bool {
let df = self.get_inner();
df.is_largest()
}
fn is_integer(&self) -> bool {
let df = self.get_inner();
df.is_integer()
}
fn scalbn(&self, n: ExpInt) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let scalbn = df.scalbn(n);
self.build_from(scalbn)
}
fn frexp(&self, exp: &mut ExpInt) -> Box<dyn FloatAttr> {
let df = self.get_inner();
let frexp_r = df.frexp(exp);
self.build_from(frexp_r)
}
fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
where
Self: Sized,
{
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use rustc_apfloat::ieee::Single;
use super::*;
use crate::builtin::attributes::FPSingleAttr;
#[test]
fn test_float_attr_give_build_qnan_neg() {
let attr = FPSingleAttr(Single::from_str("1.0").unwrap());
let qnan = attr.build_qnan(Some(42));
assert!(qnan.get_inner().is_nan());
let neg = attr.neg();
assert!(
(&*neg as &dyn Attribute)
.downcast_ref::<FPSingleAttr>()
.unwrap()
!= &attr
);
let neg_neg = neg.neg();
assert!(
(&*neg_neg as &dyn Attribute)
.downcast_ref::<FPSingleAttr>()
.is_some_and(|n| n == &attr)
);
}
}