Browse Source

Adding get_binder, for std::tuple bindings.

Samuel Jaffe 8 years ago
parent
commit
9cb0ae0cc2

+ 9 - 1
json.xcodeproj/project.pbxproj

@@ -46,6 +46,9 @@
 		CD1747431D4C216B000C344B /* example.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = example.json; sourceTree = "<group>"; };
 		CD217D8F1CCAD587007C50C6 /* json_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_test.cpp; sourceTree = "<group>"; };
 		CD217D921CCAD885007C50C6 /* json_common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_common.hpp; sourceTree = "<group>"; };
+		CD2B09881E6374F300D6D23A /* json_binder_terminate.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = json_binder_terminate.t.h; sourceTree = "<group>"; };
+		CD2B098A1E63822100D6D23A /* json_direct_get_binder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_direct_get_binder.hpp; sourceTree = "<group>"; };
+		CD2B098B1E63839A00D6D23A /* json_binder_tuple.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = json_binder_tuple.t.h; sourceTree = "<group>"; };
 		CD3C80CF1D6A711000ACC795 /* libjson-direct.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = "libjson-direct.dylib"; sourceTree = BUILT_PRODUCTS_DIR; };
 		CD472C751CCC1ABD0084C8D6 /* json_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_common.cpp; sourceTree = "<group>"; };
 		CD472C791CCC1CD80084C8D6 /* json_tuple_binder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_tuple_binder.hpp; sourceTree = "<group>"; };
@@ -103,6 +106,7 @@
 				CD472C791CCC1CD80084C8D6 /* json_tuple_binder.hpp */,
 				CD472C7A1CCC1D440084C8D6 /* json_object_binder.hpp */,
 				CD472C7E1CCC498C0084C8D6 /* json_direct_binder.hpp */,
+				CD2B098A1E63822100D6D23A /* json_direct_get_binder.hpp */,
 				CD472C7B1CCC1DA20084C8D6 /* json_direct_map_binder.hpp */,
 				CD472C7D1CCC1E120084C8D6 /* json_direct_scalar_binder.hpp */,
 				CD472C7C1CCC1DDF0084C8D6 /* json_direct_vector_binder.hpp */,
@@ -147,6 +151,8 @@
 				CD679D761E61267300F9F843 /* json_binder_value_int.t.h */,
 				CD679D7B1E61E26000F9F843 /* json_binder_value_string.t.h */,
 				CD679D7C1E6273DB00F9F843 /* json_binder_value_double.t.h */,
+				CD2B098B1E63839A00D6D23A /* json_binder_tuple.t.h */,
+				CD2B09881E6374F300D6D23A /* json_binder_terminate.t.h */,
 				CD679D781E6126C700F9F843 /* json_tc.cpp */,
 			);
 			name = test;
@@ -302,13 +308,15 @@
 				"$(SRCROOT)/json_binder_value_int.t.h",
 				"$(SRCROOT)/json_binder_value_string.t.h",
 				"$(SRCROOT)/json_binder_value_double.t.h",
+				"$(SRCROOT)/json_binder_terminate.t.h",
+				"$(SRCROOT)/json_binder_tuple.t.h",
 			);
 			outputPaths = (
 				"$(SRCDIR)/json_tc.cpp",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "cxxtestgen --error-printer -o json_tc.cpp json_binder_value_int.t.h json_binder_value_string.t.h json_binder_value_double.t.h";
+			shellScript = "cxxtestgen --error-printer -o json_tc.cpp json_binder_value_int.t.h json_binder_value_string.t.h json_binder_value_double.t.h json_binder_terminate.t.h json_binder_tuple.t.h";
 		};
 /* End PBXShellScriptBuildPhase section */
 

+ 38 - 0
json/json_direct_get_binder.hpp

@@ -0,0 +1,38 @@
+//
+//  json_direct_tuple_binder.hpp
+//  json
+//
+//  Created by Sam Jaffe on 2/26/17.
+//
+
+#pragma once
+
+namespace json { namespace binder {
+  template <typename T, std::size_t I>
+  class get_binder : public binder_impl<T> {
+  public:
+    using value_type = typename std::remove_reference<decltype(std::get<I>(std::declval<T>()))>::type;
+    
+    get_binder(binder<value_type> val_binder)
+    : impl(std::move(val_binder)) {
+      
+    }
+    
+    get_binder(binder_impl<value_type> const & val_binder = value_binder<value_type>())
+    : impl(val_binder) {
+      
+    }
+    
+    virtual binder_impl<T>* clone() const override { return new get_binder(*this); }
+    
+    virtual void parse(T& object, char const*& data, parser::options opts) const override {
+      impl.parse(std::get<I>(object), data, opts);
+    }
+    
+    virtual void write(T const& val, std::ostream & data) const override {
+      impl.write(std::get<I>(val), data);
+    }
+  private:
+    binder<value_type> impl;
+  };
+} }

+ 1 - 0
json_binder.hpp

@@ -102,6 +102,7 @@ namespace json {
 #include "json/json_direct_binder.hpp"
 #include "json/json_tuple_binder.hpp"
 #include "json/json_object_binder.hpp"
+#include "json/json_direct_get_binder.hpp"
 #include "json/json_direct_map_binder.hpp"
 #include "json/json_direct_scalar_binder.hpp"
 #include "json/json_direct_vector_binder.hpp"

+ 68 - 0
json_binder_terminate.t.h

@@ -0,0 +1,68 @@
+//
+//  json_binder_test_terminate.t.h
+//  json
+//
+//  Created by Sam Jaffe on 2/26/17.
+//
+
+#pragma once
+
+#include <cxxtest/TestSuite.h>
+#include "json_binder.hpp"
+
+using namespace json::binder;
+using namespace json::parser;
+
+class json_binder_terminate_TestSuite : public CxxTest::TestSuite {
+public:
+  void test_whitespace_breaks_parsing_numeric_token() {
+    char data[] = "10 0";
+    int out = 0;
+    value_binder<int> binder{};
+    TS_ASSERT_THROWS_NOTHING(parse(bind(out, binder), data, allow_all));
+    TS_ASSERT_EQUALS(out, 10);
+  }
+  
+  void test_unterminated_input_causes_exception_when_flagged() {
+    char data[] = "10 0";
+    int out = 0;
+    value_binder<int> binder{};
+    TS_ASSERT_THROWS(parse(bind(out, binder), data,
+                           disable_concatenated_json_bodies),
+                     json::malformed_json_exception);
+  }
+  
+  void test_does_not_crash_if_terminates_early() {
+    char data[] = "\"This is a \"string";
+    std::string out = "";
+    value_binder<std::string> binder{};
+    TS_ASSERT_THROWS_NOTHING(parse(json::binder::bind(out, binder), data, allow_all));
+    TS_ASSERT_EQUALS(out, "This is a ");
+  }
+  
+  void test_will_crash_if_terminates_with_remaining_with_option() {
+    char data[] = "\"This is a \"string";
+    std::string out = "";
+    value_binder<std::string> binder{};
+    TS_ASSERT_THROWS(parse(json::binder::bind(out, binder), data,
+                           disable_concatenated_json_bodies),
+                     json::malformed_json_exception);
+  }
+  
+  void test_will_not_crash_if_terminates_with_remaining_only_whitespace() {
+    char data[] = "\"This is a \"    ";
+    std::string out = "";
+    value_binder<std::string> binder{};
+    TS_ASSERT_THROWS_NOTHING(parse(json::binder::bind(out, binder), data,
+                                   disable_concatenated_json_bodies));
+  }
+  
+  void test_will_crash_if_terminates_with_remaining_buffered_by_whitespace() {
+    char data[] = "\"This is a \"    string";
+    std::string out = "";
+    value_binder<std::string> binder{};
+    TS_ASSERT_THROWS(parse(json::binder::bind(out, binder), data,
+                           disable_concatenated_json_bodies),
+                     json::malformed_json_exception);
+  }
+};

+ 52 - 0
json_binder_tuple.t.h

@@ -0,0 +1,52 @@
+//
+//  json_binder_tuple.t.h
+//  json
+//
+//  Created by Sam Jaffe on 2/26/17.
+//
+
+#pragma once
+
+#include <cxxtest/TestSuite.h>
+#include "json_binder.hpp"
+
+using namespace json::binder;
+using namespace json::parser;
+
+class json_binder_tuple_TestSuite : public CxxTest::TestSuite {
+public:
+  void test_bind_to_tuple() {
+    char data[] = "[ 1, 2 ]";
+    using tuple = std::tuple<int, int>;
+    tuple out = std::make_tuple(0, 0);
+    auto binder = tuple_binder<std::tuple<int, int>>()
+      (get_binder<tuple, 0>())
+      (get_binder<tuple, 1>());
+    parse(json::binder::bind(out, binder), data, allow_all);
+    TS_ASSERT_EQUALS(out, std::make_tuple(1, 2));
+  }
+  
+  void test_bind_to_tuple_throws_if_missing_entry() {
+    char data[] = "[ 1 ]";
+    using tuple = std::tuple<int, int>;
+    tuple out = std::make_tuple(0, 0);
+    auto binder = tuple_binder<std::tuple<int, int>>()
+      (get_binder<tuple, 0>())
+      (get_binder<tuple, 1>());
+    TS_ASSERT_THROWS(parse(json::binder::bind(out, binder), data, allow_all),
+                     json::malformed_json_exception);
+    TS_ASSERT_EQUALS(out, std::make_tuple(1, 0));
+  }
+
+  void test_bind_to_tuple_throws_if_too_many_entries() {
+    char data[] = "[ 1, 2, 3 ]";
+    using tuple = std::tuple<int, int>;
+    tuple out = std::make_tuple(0, 0);
+    auto binder = tuple_binder<std::tuple<int, int>>()
+      (get_binder<tuple, 0>())
+      (get_binder<tuple, 1>());
+    TS_ASSERT_THROWS(parse(json::binder::bind(out, binder), data, allow_all),
+                     json::malformed_json_exception);
+    TS_ASSERT_EQUALS(out, std::make_tuple(1, 2));
+  }
+};

+ 22 - 14
json_binder_value_int.t.h

@@ -115,29 +115,37 @@ public:
                      json::json_numeric_exception);
     TS_ASSERT_EQUALS(out, 0);
   }
-  
-  void test_whitespace_breaks_parsing_numeric_token() {
-    char data[] = "10 0";
+    
+  void test_parse_hexadecimal_number() {
+    char data[] = "0xF";
     int out = 0;
     value_binder<int> binder{};
-    TS_ASSERT_THROWS_NOTHING(parse(bind(out, binder), data, allow_all));
-    TS_ASSERT_EQUALS(out, 10);
+    parse(bind(out, binder), data, allow_all);
+    TS_ASSERT_EQUALS(out, 15);
   }
   
-  void test_unterminated_input_causes_exception_when_flagged() {
-    char data[] = "10 0";
+  void test_parse_hexadecimal_number_out_of_bounds() {
+    char data[] = "0x100000000";
     int out = 0;
     value_binder<int> binder{};
-    TS_ASSERT_THROWS(parse(bind(out, binder), data,
-                           disable_concatenated_json_bodies),
-                     json::malformed_json_exception);
+    TS_ASSERT_THROWS(parse(bind(out, binder), data, allow_all),
+                     json::json_numeric_exception);
   }
-  
-  void test_parse_hexadecimal_number() {
-    char data[] = "0xF";
+
+  void test_parse_octal_number() {
+    char data[] = "010";
     int out = 0;
     value_binder<int> binder{};
     parse(bind(out, binder), data, allow_all);
-    TS_ASSERT_EQUALS(out, 15);
+    TS_ASSERT_EQUALS(out, 8);
+  }
+  
+  void test_parse_octal_number_out_of_bounds() {
+    char data[] = "040000000000";
+    int out = 0;
+    value_binder<int> binder{};
+    TS_ASSERT_THROWS(parse(bind(out, binder), data, allow_all),
+                     json::json_numeric_exception);
   }
+
 };

+ 1 - 34
json_binder_value_string.t.h

@@ -47,38 +47,5 @@ public:
     TS_ASSERT_THROWS(parse(json::binder::bind(out, binder), data, allow_all),
                      json::unterminated_json_exception);
     TS_ASSERT_EQUALS(out, "");
-  }
-  
-  void test_does_not_crash_if_terminates_early() {
-    char data[] = "\"This is a \"string";
-    std::string out = "";
-    value_binder<std::string> binder{};
-    TS_ASSERT_THROWS_NOTHING(parse(json::binder::bind(out, binder), data, allow_all));
-  }
-  
-  void test_will_crash_if_terminates_with_remaining_with_option() {
-    char data[] = "\"This is a \"string";
-    std::string out = "";
-    value_binder<std::string> binder{};
-    TS_ASSERT_THROWS(parse(json::binder::bind(out, binder), data,
-                           disable_concatenated_json_bodies),
-                     json::malformed_json_exception);
-  }
-  
-  void test_will_not_crash_if_terminates_with_remaining_only_whitespace() {
-    char data[] = "\"This is a \"    ";
-    std::string out = "";
-    value_binder<std::string> binder{};
-    TS_ASSERT_THROWS_NOTHING(parse(json::binder::bind(out, binder), data,
-                                   disable_concatenated_json_bodies));
-  }
-  
-  void test_will_crash_if_terminates_with_remaining_buffered_by_whitespace() {
-    char data[] = "\"This is a \"    string";
-    std::string out = "";
-    value_binder<std::string> binder{};
-    TS_ASSERT_THROWS(parse(json::binder::bind(out, binder), data,
-                           disable_concatenated_json_bodies),
-                     json::malformed_json_exception);
-  }
+  }  
 };