use ifc_model::Value;
use ifc_schema::Schema;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FixedWidth(pub usize);
impl FixedWidth {
#[must_use]
pub fn from_resolved(resolved: &str) -> Option<Self> {
let upper = resolved.to_ascii_uppercase();
if !upper.contains("FIXED") {
return None;
}
let start = upper.find("STRING")?;
let open = upper[start..].find('(')? + start;
let close = upper[open..].find(')')? + open;
upper[open + 1..close].trim().parse().ok().map(Self)
}
#[must_use]
pub fn accepts(self, text: &str) -> bool {
text.chars().count() == self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Primitive {
Real,
Integer,
Text,
Boolean,
Logical,
Binary,
}
impl Primitive {
#[must_use]
pub fn from_resolved(resolved: &str) -> Option<Self> {
let token = resolved
.rsplit(|c: char| c.is_whitespace() || c == '(')
.find(|part| !part.is_empty())?
.trim_end_matches([')', ';'])
.to_ascii_uppercase();
match token.as_str() {
"REAL" | "NUMBER" => Some(Self::Real),
"INTEGER" => Some(Self::Integer),
"STRING" => Some(Self::Text),
"BOOLEAN" => Some(Self::Boolean),
"LOGICAL" => Some(Self::Logical),
"BINARY" => Some(Self::Binary),
_ => None,
}
}
#[must_use]
pub fn accepts(self, value: &Value) -> bool {
match self {
Self::Real => matches!(value, Value::Real(_) | Value::Integer(_)),
Self::Integer => matches!(value, Value::Integer(_)),
Self::Text => matches!(value, Value::Text(_)),
Self::Boolean => matches!(value, Value::Bool(_)),
Self::Logical => matches!(value, Value::Bool(_) | Value::LogicalUnknown),
Self::Binary => matches!(value, Value::Binary(_)),
}
}
#[must_use]
pub const fn describe(self) -> &'static str {
match self {
Self::Real => "a number",
Self::Integer => "an integer",
Self::Text => "a string",
Self::Boolean => "a boolean",
Self::Logical => "a logical",
Self::Binary => "binary data",
}
}
}
#[must_use]
pub fn describe_value(value: &Value) -> &'static str {
match value {
Value::Null => "unset",
Value::Derived => "derived",
Value::Bool(_) => "a boolean",
Value::LogicalUnknown => "unknown",
Value::Integer(_) => "an integer",
Value::Real(_) => "a number",
Value::Text(_) => "a string",
Value::Binary(_) => "binary data",
Value::Enum(_) => "an enumeration constant",
Value::Ref(_) => "a reference",
Value::List(_) => "an aggregate",
Value::Typed { .. } => "a typed value",
}
}
#[must_use]
pub fn primitive_of(schema: &Schema, type_name: &str) -> Option<Primitive> {
Primitive::from_resolved(&schema.resolve_defined(type_name))
}