// value.mbt — Runtime values for matcher evaluation.
//
// The evaluator works on a small dynamic value model. Casbin binds request
// and policy parameters as strings; numbers, booleans, lists, and records
// appear in matchers such as `r_sub.Age > 18` or
// `r_obj in ('data2', 'data3')`.

///|
/// A runtime value produced or consumed by the matcher evaluator.
pub(all) enum Value {
  Null
  Bool(Bool)
  Int(Int)
  Double(Double)
  String(String)
  Array(Array[Value])
  /// A record used for field access (ABAC-style attributes). Field lookup
  /// is linear and the first match wins.
  Object(Array[(String, Value)])
} derive(Eq, Debug)

///|
/// A human-readable type name used in error messages.
pub fn Value::type_name(self : Value) -> String {
  match self {
    Null => "null"
    Bool(_) => "bool"
    Int(_) => "int"
    Double(_) => "double"
    String(_) => "string"
    Array(_) => "array"
    Object(_) => "object"
  }
}

///|
/// Casbin-style equality: numbers compare across int and double, values of
/// different types are never equal, arrays compare element-wise, and
/// records compare field-wise in order.
pub fn Value::equals(self : Value, other : Value) -> Bool {
  match (self, other) {
    (Null, Null) => true
    (Bool(a), Bool(b)) => a == b
    (Int(a), Int(b)) => a == b
    (Double(a), Double(b)) => a == b
    (Int(a), Double(b)) => a.to_double() == b
    (Double(a), Int(b)) => a == b.to_double()
    (String(a), String(b)) => a == b
    (Array(a), Array(b)) => {
      let mut same = a.length() == b.length()
      if same {
        for i in 0.. {
      let mut same = a.length() == b.length()
      if same {
        for i in 0.. false
  }
}