use crate::buffer::{DType, Ints, View, Width};
use crate::error::{Error, Kind};
use std::cmp::Ordering;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Rule { Identity, Ordered, Shift, Difference }
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ByKinds { Truth(bool), Left, Right }
impl ByKinds {
pub fn ordered([left, _]: [i32; 2], result: i32, boolean: bool) -> Self {
if boolean { Self::Truth(result != 0) } else if result == left { Self::Left } else { Self::Right }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Policy { Codes { computing: DType, result: DType }, Kinds(ByKinds) }
pub(crate) fn policy(
rule: Option<Rule>, types: [DType; 2], numeric_result: DType, kinds: impl FnOnce([i32; 2]) -> Option<i32>) -> Result<Option<Policy>, Error> {
let [xc, yc] = types.map(|t| t == DType::Character);
if !xc && !yc { return Ok(None); }
let (computing, result) = match (rule, xc, yc) {
(Some(Rule::Ordered), true, true) => (DType::Integer(Width::I32), if numeric_result == DType::Boolean { DType::Boolean } else { DType::Character }),
(Some(Rule::Ordered), _, _) => {
let classes = [i32::from(xc), i32::from(yc)];
let result = kinds(classes).ok_or_else(|| Error::new(Kind::Domain, "ordered character function has no integer body"))?;
return Ok(Some(Policy::Kinds(ByKinds::ordered(classes, result, numeric_result == DType::Boolean))));
}
(Some(Rule::Difference), true, true) => (DType::Integer(Width::I32), DType::Integer(Width::I32)),
(Some(Rule::Shift), true, false) | (Some(Rule::Shift), false, true) | (Some(Rule::Difference), true, false)
if !types.iter().any(|t| matches!(t, DType::Complex(_))) =>
{ (DType::Integer(Width::I64), DType::Character) }
_ => return Err(Error::new(Kind::Domain, "function does not take these character arguments")),
};
Ok(Some(Policy::Codes { computing, result }))
}
pub fn order_of_kinds(x_character: bool, y_character: bool) -> Ordering { x_character.cmp(&y_character) }
pub fn codes(chars: &[char]) -> &[i32] {
unsafe { std::slice::from_raw_parts(chars.as_ptr().cast(), chars.len()) }
}
pub fn as_codes(view: View<'_>) -> View<'_> { match view { View::Characters(c) => View::Integers(Ints::I32(codes(c))), view => view } }