ソースを参照

fix: maybe_$type functions to fix Enum constraint

Sam Jaffe 1 年間 前
コミット
f9cb1dbdab
2 ファイル変更124 行追加8 行削除
  1. 107 0
      include/jvalidate/adapter.h
  2. 17 8
      include/jvalidate/detail/simple_adapter.h

+ 107 - 0
include/jvalidate/adapter.h

@@ -31,6 +31,113 @@ public:
   virtual Status apply_object(ObjectAdapterCallback const & cb) const = 0;
 
   virtual bool equals(Adapter const & lhs, bool strict) const = 0;
+
+  bool maybe_null(bool strict) const {
+    switch (type()) {
+    case Type::Null:
+      return true;
+    case Type::String:
+      return not strict and as_string().empty();
+    default:
+      return false;
+    }
+  }
+
+  std::optional<bool> maybe_boolean(bool strict) const {
+    switch (type()) {
+    case Type::Boolean:
+      return as_boolean();
+    case Type::String:
+      if (not strict) {
+        auto str = as_string();
+        if (str == "true") {
+          return true;
+        }
+        if (str == "false") {
+          return false;
+        }
+      }
+      return std::nullopt;
+    default:
+      return std::nullopt;
+    }
+  }
+
+  std::optional<int64_t> maybe_integer(bool strict) const {
+    switch (type()) {
+    case Type::Integer:
+      return as_integer();
+    case Type::Number: {
+      double number = as_number();
+      int64_t integer = static_cast<int64_t>(number);
+      return static_cast<double>(integer) == number ? std::make_optional(integer) : std::nullopt;
+    }
+    case Type::Boolean:
+      if (not strict) {
+        return as_boolean() ? 1 : 0;
+      }
+      return std::nullopt;
+    case Type::String:
+      if (not strict) {
+        auto str = as_string();
+        size_t end = 0;
+        int64_t rval = std::stoll(str, &end);
+        if (end == str.size()) {
+          return rval;
+        }
+      }
+      return std::nullopt;
+    default:
+      return std::nullopt;
+    }
+  }
+
+  std::optional<double> maybe_number(bool strict) const {
+    switch (type()) {
+    case Type::Number:
+      return as_number();
+    case Type::Integer:
+      return as_integer();
+    case Type::String:
+      if (not strict) {
+        auto str = as_string();
+        size_t end = 0;
+        double rval = std::stod(str, &end);
+        if (end == str.size()) {
+          return rval;
+        }
+      }
+      return std::nullopt;
+    default:
+      return std::nullopt;
+    }
+  }
+
+  std::optional<std::string> maybe_string(bool strict) const {
+    switch (type()) {
+    case Type::Null:
+      return strict ? std::nullopt : std::make_optional("");
+    case Type::String:
+      return as_string();
+    case Type::Number:
+      if (not strict) {
+        return std::to_string(as_number());
+      }
+      return std::nullopt;
+    case Type::Integer:
+      if (not strict) {
+        return std::to_string(as_integer());
+      }
+      return std::nullopt;
+    case Type::Boolean:
+      if (not strict) {
+        return as_boolean() ? "true" : "false";
+      }
+      return std::nullopt;
+    default:
+      return std::nullopt;
+    }
+  }
 };
 
 class Const {

+ 17 - 8
include/jvalidate/detail/simple_adapter.h

@@ -166,22 +166,31 @@ public:
 
   bool equals(Adapter const & rhs, bool strict = false) const final {
     Type const rhs_type = rhs.type();
-    if (strict && rhs_type != type()) {
-      return false;
-    }
 
     // TODO(samjaffe): Needs type coercion
     switch (rhs_type) {
     case Type::Null:
-      return type() == Type::Null;
+      return maybe_null(strict);
     case Type::Boolean:
-      return rhs.as_boolean() == as_boolean();
+      if (std::optional maybe = maybe_boolean(strict)) {
+        return rhs.as_boolean() == *maybe;
+      }
+      return false;
     case Type::Integer:
-      return rhs.as_integer() == as_integer();
+      if (std::optional maybe = maybe_integer(strict)) {
+        return rhs.as_integer() == *maybe;
+      }
+      return false;
     case Type::Number:
-      return rhs.as_number() == as_number();
+      if (std::optional maybe = maybe_number(strict)) {
+        return rhs.as_number() == *maybe;
+      }
+      return false;
     case Type::String:
-      return rhs.as_string() == as_string();
+      if (std::optional maybe = maybe_string(strict)) {
+        return rhs.as_string() == *maybe;
+      }
+      return false;
     case Type::Array: {
       auto array = this->as_array();
       if (rhs.array_size() != array.size()) {