ffi-yajl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (214) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +17 -0
  4. data/Rakefile +62 -0
  5. data/bin/ffi-yajl-bench +36 -0
  6. data/ext/ffi_yajl/ext/encoder/encoder.c +240 -0
  7. data/ext/ffi_yajl/ext/encoder/extconf.rb +29 -0
  8. data/ext/ffi_yajl/ext/parser/extconf.rb +29 -0
  9. data/ext/ffi_yajl/ext/parser/parser.c +199 -0
  10. data/ext/libyajl2/extconf.rb +65 -0
  11. data/ext/libyajl2/vendored/.gitignore +3 -0
  12. data/ext/libyajl2/vendored/BUILDING +23 -0
  13. data/ext/libyajl2/vendored/BUILDING.win32 +27 -0
  14. data/ext/libyajl2/vendored/CMakeLists.txt +79 -0
  15. data/ext/libyajl2/vendored/COPYING +13 -0
  16. data/ext/libyajl2/vendored/ChangeLog +175 -0
  17. data/ext/libyajl2/vendored/README +74 -0
  18. data/ext/libyajl2/vendored/TODO +9 -0
  19. data/ext/libyajl2/vendored/YAJLDoc.cmake +26 -0
  20. data/ext/libyajl2/vendored/configure +79 -0
  21. data/ext/libyajl2/vendored/example/CMakeLists.txt +23 -0
  22. data/ext/libyajl2/vendored/example/README.md +7 -0
  23. data/ext/libyajl2/vendored/example/parse_config.c +69 -0
  24. data/ext/libyajl2/vendored/example/sample.config +101 -0
  25. data/ext/libyajl2/vendored/perf/CMakeLists.txt +23 -0
  26. data/ext/libyajl2/vendored/perf/documents.c +1418 -0
  27. data/ext/libyajl2/vendored/perf/documents.h +28 -0
  28. data/ext/libyajl2/vendored/perf/perftest.c +134 -0
  29. data/ext/libyajl2/vendored/reformatter/CMakeLists.txt +39 -0
  30. data/ext/libyajl2/vendored/reformatter/json_reformat.c +194 -0
  31. data/ext/libyajl2/vendored/src/CMakeLists.txt +86 -0
  32. data/ext/libyajl2/vendored/src/YAJL.dxy +1258 -0
  33. data/ext/libyajl2/vendored/src/api/yajl_common.h +75 -0
  34. data/ext/libyajl2/vendored/src/api/yajl_gen.h +157 -0
  35. data/ext/libyajl2/vendored/src/api/yajl_parse.h +226 -0
  36. data/ext/libyajl2/vendored/src/api/yajl_tree.h +185 -0
  37. data/ext/libyajl2/vendored/src/api/yajl_version.h.cmake +23 -0
  38. data/ext/libyajl2/vendored/src/yajl +33 -0
  39. data/ext/libyajl2/vendored/src/yajl.c +175 -0
  40. data/ext/libyajl2/vendored/src/yajl.pc.cmake +9 -0
  41. data/ext/libyajl2/vendored/src/yajl_alloc.c +52 -0
  42. data/ext/libyajl2/vendored/src/yajl_alloc.h +34 -0
  43. data/ext/libyajl2/vendored/src/yajl_buf.c +103 -0
  44. data/ext/libyajl2/vendored/src/yajl_buf.h +57 -0
  45. data/ext/libyajl2/vendored/src/yajl_bytestack.h +69 -0
  46. data/ext/libyajl2/vendored/src/yajl_encode.c +220 -0
  47. data/ext/libyajl2/vendored/src/yajl_encode.h +34 -0
  48. data/ext/libyajl2/vendored/src/yajl_gen.c +354 -0
  49. data/ext/libyajl2/vendored/src/yajl_lex.c +763 -0
  50. data/ext/libyajl2/vendored/src/yajl_lex.h +117 -0
  51. data/ext/libyajl2/vendored/src/yajl_parser.c +498 -0
  52. data/ext/libyajl2/vendored/src/yajl_parser.h +78 -0
  53. data/ext/libyajl2/vendored/src/yajl_tree.c +503 -0
  54. data/ext/libyajl2/vendored/src/yajl_version.c +7 -0
  55. data/ext/libyajl2/vendored/test/CMakeLists.txt +23 -0
  56. data/ext/libyajl2/vendored/test/cases/ac_difficult_json_c_test_case_with_comments.json +1 -0
  57. data/ext/libyajl2/vendored/test/cases/ac_difficult_json_c_test_case_with_comments.json.gold +36 -0
  58. data/ext/libyajl2/vendored/test/cases/ac_simple_with_comments.json +11 -0
  59. data/ext/libyajl2/vendored/test/cases/ac_simple_with_comments.json.gold +9 -0
  60. data/ext/libyajl2/vendored/test/cases/ag_false_then_garbage.json +1 -0
  61. data/ext/libyajl2/vendored/test/cases/ag_false_then_garbage.json.gold +2 -0
  62. data/ext/libyajl2/vendored/test/cases/ag_null_then_garbage.json +1 -0
  63. data/ext/libyajl2/vendored/test/cases/ag_null_then_garbage.json.gold +2 -0
  64. data/ext/libyajl2/vendored/test/cases/ag_true_then_garbage.json +1 -0
  65. data/ext/libyajl2/vendored/test/cases/ag_true_then_garbage.json.gold +2 -0
  66. data/ext/libyajl2/vendored/test/cases/am_eof.json +1 -0
  67. data/ext/libyajl2/vendored/test/cases/am_eof.json.gold +4 -0
  68. data/ext/libyajl2/vendored/test/cases/am_integers.json +1 -0
  69. data/ext/libyajl2/vendored/test/cases/am_integers.json.gold +3 -0
  70. data/ext/libyajl2/vendored/test/cases/am_multiple.json +3 -0
  71. data/ext/libyajl2/vendored/test/cases/am_multiple.json.gold +5 -0
  72. data/ext/libyajl2/vendored/test/cases/am_stuff.json +7 -0
  73. data/ext/libyajl2/vendored/test/cases/am_stuff.json.gold +14 -0
  74. data/ext/libyajl2/vendored/test/cases/ap_array_open.json +1 -0
  75. data/ext/libyajl2/vendored/test/cases/ap_array_open.json.gold +2 -0
  76. data/ext/libyajl2/vendored/test/cases/ap_eof_str.json +1 -0
  77. data/ext/libyajl2/vendored/test/cases/ap_eof_str.json.gold +1 -0
  78. data/ext/libyajl2/vendored/test/cases/ap_map_open.json +1 -0
  79. data/ext/libyajl2/vendored/test/cases/ap_map_open.json.gold +2 -0
  80. data/ext/libyajl2/vendored/test/cases/ap_partial_ok.json +1 -0
  81. data/ext/libyajl2/vendored/test/cases/ap_partial_ok.json.gold +4 -0
  82. data/ext/libyajl2/vendored/test/cases/array.json +6 -0
  83. data/ext/libyajl2/vendored/test/cases/array.json.gold +22 -0
  84. data/ext/libyajl2/vendored/test/cases/array_close.json +1 -0
  85. data/ext/libyajl2/vendored/test/cases/array_close.json.gold +2 -0
  86. data/ext/libyajl2/vendored/test/cases/bignums.json +1 -0
  87. data/ext/libyajl2/vendored/test/cases/bignums.json.gold +5 -0
  88. data/ext/libyajl2/vendored/test/cases/bogus_char.json +4 -0
  89. data/ext/libyajl2/vendored/test/cases/bogus_char.json.gold +10 -0
  90. data/ext/libyajl2/vendored/test/cases/codepoints_from_unicode_org.json +1 -0
  91. data/ext/libyajl2/vendored/test/cases/codepoints_from_unicode_org.json.gold +2 -0
  92. data/ext/libyajl2/vendored/test/cases/deep_arrays.json +1 -0
  93. data/ext/libyajl2/vendored/test/cases/deep_arrays.json.gold +2049 -0
  94. data/ext/libyajl2/vendored/test/cases/difficult_json_c_test_case.json +1 -0
  95. data/ext/libyajl2/vendored/test/cases/difficult_json_c_test_case.json.gold +36 -0
  96. data/ext/libyajl2/vendored/test/cases/doubles.json +1 -0
  97. data/ext/libyajl2/vendored/test/cases/doubles.json.gold +7 -0
  98. data/ext/libyajl2/vendored/test/cases/doubles_in_array.json +1 -0
  99. data/ext/libyajl2/vendored/test/cases/doubles_in_array.json.gold +8 -0
  100. data/ext/libyajl2/vendored/test/cases/empty_array.json +1 -0
  101. data/ext/libyajl2/vendored/test/cases/empty_array.json.gold +3 -0
  102. data/ext/libyajl2/vendored/test/cases/empty_string.json +1 -0
  103. data/ext/libyajl2/vendored/test/cases/empty_string.json.gold +2 -0
  104. data/ext/libyajl2/vendored/test/cases/escaped_bulgarian.json +4 -0
  105. data/ext/libyajl2/vendored/test/cases/escaped_bulgarian.json.gold +7 -0
  106. data/ext/libyajl2/vendored/test/cases/escaped_foobar.json +1 -0
  107. data/ext/libyajl2/vendored/test/cases/escaped_foobar.json.gold +2 -0
  108. data/ext/libyajl2/vendored/test/cases/false.json +1 -0
  109. data/ext/libyajl2/vendored/test/cases/false.json.gold +2 -0
  110. data/ext/libyajl2/vendored/test/cases/fg_false_then_garbage.json +1 -0
  111. data/ext/libyajl2/vendored/test/cases/fg_false_then_garbage.json.gold +3 -0
  112. data/ext/libyajl2/vendored/test/cases/fg_issue_7.json +1 -0
  113. data/ext/libyajl2/vendored/test/cases/fg_issue_7.json.gold +3 -0
  114. data/ext/libyajl2/vendored/test/cases/fg_null_then_garbage.json +1 -0
  115. data/ext/libyajl2/vendored/test/cases/fg_null_then_garbage.json.gold +3 -0
  116. data/ext/libyajl2/vendored/test/cases/fg_true_then_garbage.json +1 -0
  117. data/ext/libyajl2/vendored/test/cases/fg_true_then_garbage.json.gold +3 -0
  118. data/ext/libyajl2/vendored/test/cases/four_byte_utf8.json +2 -0
  119. data/ext/libyajl2/vendored/test/cases/four_byte_utf8.json.gold +5 -0
  120. data/ext/libyajl2/vendored/test/cases/high_overflow.json +1 -0
  121. data/ext/libyajl2/vendored/test/cases/high_overflow.json.gold +2 -0
  122. data/ext/libyajl2/vendored/test/cases/integers.json +3 -0
  123. data/ext/libyajl2/vendored/test/cases/integers.json.gold +14 -0
  124. data/ext/libyajl2/vendored/test/cases/invalid_utf8.json +1 -0
  125. data/ext/libyajl2/vendored/test/cases/invalid_utf8.json.gold +3 -0
  126. data/ext/libyajl2/vendored/test/cases/isolated_surrogate_marker.json +1 -0
  127. data/ext/libyajl2/vendored/test/cases/isolated_surrogate_marker.json.gold +2 -0
  128. data/ext/libyajl2/vendored/test/cases/leading_zero_in_number.json +1 -0
  129. data/ext/libyajl2/vendored/test/cases/leading_zero_in_number.json.gold +5 -0
  130. data/ext/libyajl2/vendored/test/cases/lonely_minus_sign.json +7 -0
  131. data/ext/libyajl2/vendored/test/cases/lonely_minus_sign.json.gold +9 -0
  132. data/ext/libyajl2/vendored/test/cases/lonely_number.json +1 -0
  133. data/ext/libyajl2/vendored/test/cases/lonely_number.json.gold +2 -0
  134. data/ext/libyajl2/vendored/test/cases/low_overflow.json +1 -0
  135. data/ext/libyajl2/vendored/test/cases/low_overflow.json.gold +2 -0
  136. data/ext/libyajl2/vendored/test/cases/map_close.json +1 -0
  137. data/ext/libyajl2/vendored/test/cases/map_close.json.gold +2 -0
  138. data/ext/libyajl2/vendored/test/cases/missing_integer_after_decimal_point.json +1 -0
  139. data/ext/libyajl2/vendored/test/cases/missing_integer_after_decimal_point.json.gold +2 -0
  140. data/ext/libyajl2/vendored/test/cases/missing_integer_after_exponent.json +1 -0
  141. data/ext/libyajl2/vendored/test/cases/missing_integer_after_exponent.json.gold +2 -0
  142. data/ext/libyajl2/vendored/test/cases/multiple.json +3 -0
  143. data/ext/libyajl2/vendored/test/cases/multiple.json.gold +4 -0
  144. data/ext/libyajl2/vendored/test/cases/non_utf8_char_in_string.json +1 -0
  145. data/ext/libyajl2/vendored/test/cases/non_utf8_char_in_string.json.gold +8 -0
  146. data/ext/libyajl2/vendored/test/cases/np_partial_bad.json +1 -0
  147. data/ext/libyajl2/vendored/test/cases/np_partial_bad.json.gold +5 -0
  148. data/ext/libyajl2/vendored/test/cases/null.json +1 -0
  149. data/ext/libyajl2/vendored/test/cases/null.json.gold +2 -0
  150. data/ext/libyajl2/vendored/test/cases/nulls_and_bools.json +5 -0
  151. data/ext/libyajl2/vendored/test/cases/nulls_and_bools.json.gold +9 -0
  152. data/ext/libyajl2/vendored/test/cases/simple.json +5 -0
  153. data/ext/libyajl2/vendored/test/cases/simple.json.gold +9 -0
  154. data/ext/libyajl2/vendored/test/cases/simple_with_comments.json +11 -0
  155. data/ext/libyajl2/vendored/test/cases/simple_with_comments.json.gold +5 -0
  156. data/ext/libyajl2/vendored/test/cases/string_invalid_escape.json +1 -0
  157. data/ext/libyajl2/vendored/test/cases/string_invalid_escape.json.gold +3 -0
  158. data/ext/libyajl2/vendored/test/cases/string_invalid_hex_char.json +1 -0
  159. data/ext/libyajl2/vendored/test/cases/string_invalid_hex_char.json.gold +2 -0
  160. data/ext/libyajl2/vendored/test/cases/string_with_escapes.json +3 -0
  161. data/ext/libyajl2/vendored/test/cases/string_with_escapes.json.gold +7 -0
  162. data/ext/libyajl2/vendored/test/cases/string_with_invalid_newline.json +2 -0
  163. data/ext/libyajl2/vendored/test/cases/string_with_invalid_newline.json.gold +2 -0
  164. data/ext/libyajl2/vendored/test/cases/three_byte_utf8.json +1 -0
  165. data/ext/libyajl2/vendored/test/cases/three_byte_utf8.json.gold +7 -0
  166. data/ext/libyajl2/vendored/test/cases/true.json +1 -0
  167. data/ext/libyajl2/vendored/test/cases/true.json.gold +2 -0
  168. data/ext/libyajl2/vendored/test/cases/unescaped_bulgarian.json +1 -0
  169. data/ext/libyajl2/vendored/test/cases/unescaped_bulgarian.json.gold +4 -0
  170. data/ext/libyajl2/vendored/test/cases/zerobyte.json +1 -0
  171. data/ext/libyajl2/vendored/test/cases/zerobyte.json.gold +0 -0
  172. data/ext/libyajl2/vendored/test/run_tests.sh +94 -0
  173. data/ext/libyajl2/vendored/test/yajl_test.c +281 -0
  174. data/ext/libyajl2/vendored/verify/CMakeLists.txt +39 -0
  175. data/ext/libyajl2/vendored/verify/json_verify.c +116 -0
  176. data/lib/ffi_yajl.rb +14 -0
  177. data/lib/ffi_yajl/benchmark.rb +7 -0
  178. data/lib/ffi_yajl/benchmark/MIT-LICENSE +20 -0
  179. data/lib/ffi_yajl/benchmark/encode.rb +135 -0
  180. data/lib/ffi_yajl/benchmark/encode_json_and_marshal.rb +42 -0
  181. data/lib/ffi_yajl/benchmark/encode_json_and_yaml.rb +53 -0
  182. data/lib/ffi_yajl/benchmark/encode_profile.rb +38 -0
  183. data/lib/ffi_yajl/benchmark/http.rb +32 -0
  184. data/lib/ffi_yajl/benchmark/parse.rb +133 -0
  185. data/lib/ffi_yajl/benchmark/parse_json_and_marshal.rb +50 -0
  186. data/lib/ffi_yajl/benchmark/parse_json_and_yaml.rb +55 -0
  187. data/lib/ffi_yajl/benchmark/parse_profile.rb +37 -0
  188. data/lib/ffi_yajl/benchmark/parse_profile_ruby_prof.rb +39 -0
  189. data/lib/ffi_yajl/benchmark/parse_stream.rb +54 -0
  190. data/lib/ffi_yajl/benchmark/subjects/item.json +1 -0
  191. data/lib/ffi_yajl/benchmark/subjects/ohai.json +1216 -0
  192. data/lib/ffi_yajl/benchmark/subjects/ohai.marshal_dump +0 -0
  193. data/lib/ffi_yajl/benchmark/subjects/ohai.yml +975 -0
  194. data/lib/ffi_yajl/benchmark/subjects/twitter_search.json +1 -0
  195. data/lib/ffi_yajl/benchmark/subjects/twitter_stream.json +430 -0
  196. data/lib/ffi_yajl/benchmark/subjects/unicode.json +1 -0
  197. data/lib/ffi_yajl/encoder.rb +53 -0
  198. data/lib/ffi_yajl/ext.rb +22 -0
  199. data/lib/ffi_yajl/ext/.keep +0 -0
  200. data/lib/ffi_yajl/ffi.rb +129 -0
  201. data/lib/ffi_yajl/ffi/encoder.rb +175 -0
  202. data/lib/ffi_yajl/ffi/parser.rb +145 -0
  203. data/lib/ffi_yajl/json_gem.rb +121 -0
  204. data/lib/ffi_yajl/parser.rb +23 -0
  205. data/lib/ffi_yajl/version.rb +3 -0
  206. data/lib/libyajl.so +0 -0
  207. data/lib/libyajl.so.2 +0 -0
  208. data/lib/libyajl.so.2.0.5 +0 -0
  209. data/lib/libyajl_s.a +0 -0
  210. data/spec/ffi_yajl/encoder_spec.rb +39 -0
  211. data/spec/ffi_yajl/json_gem_spec.rb +355 -0
  212. data/spec/ffi_yajl/parser_spec.rb +78 -0
  213. data/spec/spec_helper.rb +14 -0
  214. metadata +332 -0
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+
3
+ require 'ffi_yajl/encoder'
4
+ require 'ffi_yajl/parser'
5
+
6
+ unless RUBY_VERSION.to_f >= 1.9
7
+ # segfaults on ruby 1.8 and this is an exceedingly low priority to fix, use ffi instead
8
+ raise NotImplementedError, "The C-extension is disabled on Ruby 1.8"
9
+ end
10
+
11
+ module FFI_Yajl
12
+ class Parser
13
+ require 'ffi_yajl/ext/parser'
14
+ include FFI_Yajl::Ext::Parser
15
+ end
16
+
17
+ class Encoder
18
+ require 'ffi_yajl/ext/encoder'
19
+ include FFI_Yajl::Ext::Encoder
20
+ end
21
+ end
22
+
File without changes
@@ -0,0 +1,129 @@
1
+ require 'rubygems'
2
+
3
+ require 'ffi'
4
+
5
+ module FFI_Yajl
6
+ extend ::FFI::Library
7
+
8
+ libname = ::FFI.map_library_name("yajl")
9
+ libpath = File.expand_path(File.join(File.dirname(__FILE__), "..", libname))
10
+
11
+ if File.file?(libpath)
12
+ # use our vendored version of libyajl2 if we find it installed
13
+ ffi_lib libpath
14
+ else
15
+ ffi_lib 'yajl'
16
+ end
17
+
18
+ class YajlCallbacks < ::FFI::Struct
19
+ layout :yajl_null, :pointer,
20
+ :yajl_boolean, :pointer,
21
+ :yajl_integer, :pointer,
22
+ :yajl_double, :pointer,
23
+ :yajl_number, :pointer,
24
+ :yajl_string, :pointer,
25
+ :yajl_start_map, :pointer,
26
+ :yajl_map_key, :pointer,
27
+ :yajl_end_map, :pointer,
28
+ :yajl_start_array, :pointer,
29
+ :yajl_end_array, :pointer
30
+ end
31
+
32
+ enum :yajl_status, [
33
+ :yajl_status_ok,
34
+ :yajl_status_client_canceled,
35
+ :yajl_status_insufficient_data,
36
+ :yajl_status_error,
37
+ ]
38
+
39
+ # FFI::Enums are slow, should remove the rest
40
+ # enum :yajl_gen_status, [
41
+ # :yajl_gen_status_ok,
42
+ # :yajl_gen_keys_must_be_strings,
43
+ # :yajl_max_depth_exceeded,
44
+ # :yajl_gen_in_error_state,
45
+ # :yajl_gen_generation_complete,
46
+ # :yajl_gen_invalid_number,
47
+ # :yajl_gen_no_buf,
48
+ # ]
49
+
50
+ enum :yajl_option, [
51
+ :yajl_allow_comments, 0x01,
52
+ :yajl_dont_validate_strings, 0x02,
53
+ :yajl_allow_trailing_garbage, 0x04,
54
+ :yajl_allow_multiple_values, 0x08,
55
+ :yajl_allow_partial_values, 0x10,
56
+ ]
57
+
58
+ enum :yajl_gen_option, [
59
+ :yajl_gen_beautify, 0x01,
60
+ :yajl_gen_indent_string, 0x02,
61
+ :yajl_gen_print_callback, 0x04,
62
+ :yajl_gen_validate_utf8, 0x08,
63
+ ]
64
+
65
+ typedef :pointer, :yajl_handle
66
+ typedef :pointer, :yajl_gen
67
+
68
+ # yajl uses unsinged char *'s consistently
69
+ typedef :pointer, :ustring_pointer
70
+ typedef :string, :ustring
71
+
72
+ # const char *yajl_status_to_string (yajl_status code)
73
+ attach_function :yajl_status_to_string, [ :yajl_status ], :string
74
+ # yajl_handle yajl_alloc(const yajl_callbacks * callbacks, yajl_alloc_funcs * afs, void * ctx)
75
+ attach_function :yajl_alloc, [:pointer, :pointer, :pointer], :yajl_handle
76
+ # void yajl_free (yajl_handle handle)
77
+ attach_function :yajl_free, [:yajl_handle], :void
78
+ # yajl_status yajl_parse (yajl_handle hand, const unsigned char *jsonText, unsigned int jsonTextLength)
79
+ attach_function :yajl_parse, [:yajl_handle, :ustring, :uint], :yajl_status
80
+ # yajl_status yajl_parse_complete (yajl_handle hand)
81
+ attach_function :yajl_complete_parse, [:yajl_handle], :yajl_status
82
+ # unsigned char *yajl_get_error (yajl_handle hand, int verbose, const unsigned char *jsonText, unsigned int jsonTextLength)
83
+ attach_function :yajl_get_error, [:yajl_handle, :int, :ustring, :int], :ustring
84
+ # void yajl_free_error (yajl_handle hand, unsigned char *str)
85
+ attach_function :yajl_free_error, [:yajl_handle, :ustring], :void
86
+
87
+ #
88
+ attach_function :yajl_config, [:yajl_handle, :yajl_option, :int], :int
89
+
90
+ attach_function :yajl_gen_config, [:yajl_gen, :yajl_gen_option, :varargs], :int
91
+
92
+ # yajl_gen yajl_gen_alloc (const yajl_alloc_funcs *allocFuncs)
93
+ attach_function :yajl_gen_alloc, [:pointer], :yajl_gen
94
+ # yajl_gen yajl_gen_alloc2 (const yajl_print_t callback, const yajl_gen_config *config, const yajl_alloc_funcs *allocFuncs, void *ctx)
95
+ # attach_function :yajl_gen_alloc2, [:pointer, :pointer, :pointer, :pointer], :yajl_gen
96
+ # void yajl_gen_free (yajl_gen handle)
97
+ attach_function :yajl_gen_free, [:yajl_gen], :void
98
+
99
+ attach_function :yajl_gen_integer, [:yajl_gen, :long_long], :int
100
+ attach_function :yajl_gen_double, [:yajl_gen, :double], :int
101
+ attach_function :yajl_gen_number, [:yajl_gen, :ustring, :int], :int
102
+ attach_function :yajl_gen_string, [:yajl_gen, :ustring, :int], :int
103
+ attach_function :yajl_gen_null, [:yajl_gen], :int
104
+ attach_function :yajl_gen_bool, [:yajl_gen, :int], :int
105
+ attach_function :yajl_gen_map_open, [:yajl_gen], :int
106
+ attach_function :yajl_gen_map_close, [:yajl_gen], :int
107
+ attach_function :yajl_gen_array_open, [:yajl_gen], :int
108
+ attach_function :yajl_gen_array_close, [:yajl_gen], :int
109
+ # yajl_gen_status yajl_gen_get_buf (yajl_gen hand, const unsigned char **buf, unsigned int *len)
110
+ attach_function :yajl_gen_get_buf, [:yajl_gen, :pointer ,:pointer], :int
111
+ # void yajl_gen_clear (yajl_gen hand)
112
+ attach_function :yajl_gen_clear, [:yajl_gen], :void
113
+
114
+ end
115
+
116
+ require 'ffi_yajl/encoder'
117
+ require 'ffi_yajl/parser'
118
+
119
+ module FFI_Yajl
120
+ class Parser
121
+ require 'ffi_yajl/ffi/parser'
122
+ include FFI_Yajl::FFI::Parser
123
+ end
124
+
125
+ class Encoder
126
+ require 'ffi_yajl/ffi/encoder'
127
+ include FFI_Yajl::FFI::Encoder
128
+ end
129
+ end
@@ -0,0 +1,175 @@
1
+
2
+ require 'ffi_yajl/ffi'
3
+
4
+ module FFI_Yajl
5
+ module FFI
6
+ module Encoder
7
+ def do_yajl_encode(obj, yajl_gen_opts = {})
8
+
9
+ yajl_gen = FFI_Yajl.yajl_gen_alloc(nil);
10
+
11
+ # configure the yajl encoder
12
+ if yajl_gen_opts[:yajl_gen_beautify]
13
+ FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_beautify, :int, 1)
14
+ end
15
+ if yajl_gen_opts[:yajl_gen_validate_utf8]
16
+ FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_validate_utf8, :int, 1)
17
+ end
18
+ indent = yajl_gen_opts[:yajl_gen_indent_string] || " "
19
+ FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_indent_string, :string, indent)
20
+
21
+ # setup our own state
22
+ state = {
23
+ :json_opts => opts,
24
+ :processing_key => false,
25
+ }
26
+
27
+ # do the encoding
28
+ obj.ffi_yajl(yajl_gen, state)
29
+
30
+ # get back our encoded JSON
31
+ string_ptr = ::FFI::MemoryPointer.new(:string)
32
+ length_ptr = ::FFI::MemoryPointer.new(:int)
33
+ if ( status = FFI_Yajl.yajl_gen_get_buf(yajl_gen, string_ptr, length_ptr) ) != 0
34
+ FFI_Yajl::Encoder.raise_error_for_status(status)
35
+ end
36
+ length = length_ptr.read_int
37
+ string = string_ptr.get_pointer(0).read_string
38
+
39
+ FFI_Yajl.yajl_gen_free(yajl_gen)
40
+
41
+ return string
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+
48
+ class Hash
49
+ def ffi_yajl(yajl_gen, state)
50
+ if ( status = FFI_Yajl.yajl_gen_map_open(yajl_gen) ) != 0
51
+ FFI_Yajl::Encoder.raise_error_for_status(status)
52
+ end
53
+ self.each do |key, value|
54
+ # Perf Fix: mutate state hash rather than creating new copy
55
+ state[:processing_key] = true
56
+ key.ffi_yajl(yajl_gen, state)
57
+ state[:processing_key] = false
58
+ value.ffi_yajl(yajl_gen, state)
59
+ end
60
+ if ( status = FFI_Yajl.yajl_gen_map_close(yajl_gen) ) != 0
61
+ FFI_Yajl::Encoder.raise_error_for_status(status)
62
+ end
63
+ end
64
+ end
65
+
66
+ class Array
67
+ def ffi_yajl(yajl_gen, state)
68
+ if ( status = FFI_Yajl.yajl_gen_array_open(yajl_gen) ) != 0
69
+ FFI_Yajl::Encoder.raise_error_for_status(status)
70
+ end
71
+ self.each do |value|
72
+ value.ffi_yajl(yajl_gen, state)
73
+ end
74
+ if ( status = FFI_Yajl.yajl_gen_array_close(yajl_gen) ) != 0
75
+ FFI_Yajl::Encoder.raise_error_for_status(status)
76
+ end
77
+ end
78
+ end
79
+
80
+ class NilClass
81
+ def ffi_yajl(yajl_gen, state)
82
+ if ( status = FFI_Yajl.yajl_gen_null(yajl_gen) ) != 0
83
+ FFI_Yajl::Encoder.raise_error_for_status(status)
84
+ end
85
+ end
86
+ end
87
+
88
+ class TrueClass
89
+ def ffi_yajl(yajl_gen, state)
90
+ if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 1) ) != 0
91
+ FFI_Yajl::Encoder.raise_error_for_status(status)
92
+ end
93
+ end
94
+ end
95
+
96
+ class FalseClass
97
+ def ffi_yajl(yajl_gen, state)
98
+ if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 0) ) != 0
99
+ FFI_Yajl::Encoder.raise_error_for_status(status)
100
+ end
101
+ end
102
+ end
103
+
104
+ class Fixnum
105
+ def ffi_yajl(yajl_gen, state)
106
+ str = self.to_s
107
+ if str == "NaN" || str == "Infinity" || str == "-Infinity"
108
+ raise ::FFI_Yajl::EncodeError.new("'#{str}' is an invalid number")
109
+ end
110
+ if state[:processing_key]
111
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
112
+ FFI_Yajl::Encoder.raise_error_for_status(status)
113
+ end
114
+ else
115
+ if ( status = FFI_Yajl.yajl_gen_integer(yajl_gen, self) ) != 0
116
+ FFI_Yajl::Encoder.raise_error_for_status(status)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ class Bignum
123
+ def ffi_yajl(yajl_gen, state)
124
+ str = self.to_s
125
+ if str == "NaN" || str == "Infinity" || str == "-Infinity"
126
+ raise ::FFI_Yajl::EncodeError.new("'#{str}' is an invalid number")
127
+ end
128
+ if state[:processing_key]
129
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
130
+ FFI_Yajl::Encoder.raise_error_for_status(status)
131
+ end
132
+ else
133
+ if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, str, str.bytesize) ) != 0
134
+ FFI_Yajl::Encoder.raise_error_for_status(status)
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ class Float
141
+ def ffi_yajl(yajl_gen, state)
142
+ str = self.to_s
143
+ if str == "NaN" || str == "Infinity" || str == "-Infinity"
144
+ raise ::FFI_Yajl::EncodeError.new("'#{str}' is an invalid number")
145
+ end
146
+ if state[:processing_key]
147
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
148
+ FFI_Yajl::Encoder.raise_error_for_status(status)
149
+ end
150
+ else
151
+ if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, str, str.bytesize) ) != 0
152
+ FFI_Yajl::Encoder.raise_error_for_status(status)
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ class String
159
+ def ffi_yajl(yajl_gen, state)
160
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, self, self.bytesize) ) != 0
161
+ FFI_Yajl::Encoder.raise_error_for_status(status)
162
+ end
163
+ end
164
+ end
165
+
166
+ # I feel dirty
167
+ class Object
168
+ def ffi_yajl(yajl_gen, state)
169
+ json = self.to_json(state[:json_opts])
170
+ if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, json, json.bytesize) ) != 0
171
+ FFI_Yajl::Encoder.raise_error_for_status(status)
172
+ end
173
+ end
174
+ end
175
+
@@ -0,0 +1,145 @@
1
+
2
+ require 'ffi_yajl/ffi'
3
+
4
+ module FFI_Yajl
5
+ module FFI
6
+ module Parser
7
+ attr_accessor :stack, :key_stack, :key, :finished
8
+
9
+ #
10
+ # stack used to build up our complex object
11
+ #
12
+ def stack
13
+ @stack ||= Array.new
14
+ end
15
+
16
+ def set_value(val)
17
+ case stack.last
18
+ when Hash
19
+ raise FFI_Yajl::ParseError.new("internal error: missing key in parse") if key.nil?
20
+ stack.last[key] = val
21
+ when Array
22
+ stack.last.push(val)
23
+ else
24
+ raise FFI_Yajl::ParseError.new("internal error: object not a hash or array")
25
+ end
26
+ end
27
+
28
+ def stack_pop
29
+ if stack.length > 1
30
+ set_value( stack.pop )
31
+ else
32
+ @finished = stack.pop
33
+ end
34
+ end
35
+
36
+ #
37
+ # stack to keep track of keys as we create nested hashes
38
+ #
39
+ def key_stack
40
+ @key_stack ||= Array.new
41
+ end
42
+
43
+ def key_push
44
+ key_stack.push(key)
45
+ end
46
+
47
+ def key_pop
48
+ @key = key_stack.pop()
49
+ end
50
+
51
+
52
+ def setup_callbacks
53
+ @null_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
54
+ set_value(nil)
55
+ 1
56
+ end
57
+ @boolean_callback = ::FFI::Function.new(:int, [:pointer, :int]) do |ctx, boolval|
58
+ set_value(boolval == 1 ? true : false)
59
+ 1
60
+ end
61
+ @integer_callback = ::FFI::Function.new(:int, [:pointer, :long_long]) do |ctx, intval|
62
+ set_value(intval)
63
+ 1
64
+ end
65
+ @number_callback = ::FFI::Function.new(:int, [:pointer, :string, :size_t ]) do |ctx, stringval, stringlen|
66
+ s = stringval.slice(0,stringlen)
67
+ s.force_encoding('UTF-8') if defined? Encoding
68
+ # XXX: I can't think of a better way to do this right now. need to call to_f if and only if its a float.
69
+ v = ( s =~ /\./ ) ? s.to_f : s.to_i
70
+ set_value(v)
71
+ 1
72
+ end
73
+ @double_callback = ::FFI::Function.new(:int, [:pointer, :double]) do |ctx, doubleval|
74
+ set_value(doubleval)
75
+ 1
76
+ end
77
+ @string_callback = ::FFI::Function.new(:int, [:pointer, :string, :size_t]) do |ctx, stringval, stringlen|
78
+ s = stringval.slice(0,stringlen)
79
+ s.force_encoding('UTF-8') if defined? Encoding
80
+ set_value(s)
81
+ 1
82
+ end
83
+ @start_map_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
84
+ key_push # for key => { } case, save the key
85
+ stack.push(Hash.new)
86
+ 1
87
+ end
88
+ @map_key_callback = ::FFI::Function.new(:int, [:pointer, :string, :size_t]) do |ctx, key, keylen|
89
+ s = key.slice(0,keylen)
90
+ s.force_encoding('UTF-8') if defined? Encoding
91
+ self.key = s
92
+ 1
93
+ end
94
+ @end_map_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
95
+ key_pop
96
+ stack_pop
97
+ 1
98
+ end
99
+ @start_array_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
100
+ key_push # for key => [ ] case, save the key
101
+ stack.push(Array.new)
102
+ 1
103
+ end
104
+ @end_array_callback = ::FFI::Function.new(:int, [:pointer]) do |ctx|
105
+ key_pop
106
+ stack_pop
107
+ 1
108
+ end
109
+ end
110
+
111
+
112
+ def do_yajl_parse(str, opts = {})
113
+ setup_callbacks
114
+ callback_ptr = ::FFI::MemoryPointer.new(::FFI_Yajl::YajlCallbacks)
115
+ callbacks = ::FFI_Yajl::YajlCallbacks.new(callback_ptr)
116
+ callbacks[:yajl_null] = @null_callback
117
+ callbacks[:yajl_boolean] = @boolean_callback
118
+ callbacks[:yajl_integer] = @integer_callback
119
+ callbacks[:yajl_double] = @double_callback
120
+ callbacks[:yajl_number] = @number_callback
121
+ callbacks[:yajl_string] = @string_callback
122
+ callbacks[:yajl_start_map] = @start_map_callback
123
+ callbacks[:yajl_map_key] = @map_key_callback
124
+ callbacks[:yajl_end_map] = @end_map_callback
125
+ callbacks[:yajl_start_array] = @start_array_callback
126
+ callbacks[:yajl_end_array] = @end_array_callback
127
+ yajl_handle = ::FFI_Yajl.yajl_alloc(callback_ptr, nil, nil)
128
+ if ( stat = ::FFI_Yajl.yajl_parse(yajl_handle, str, str.bytesize) != :yajl_status_ok )
129
+ # FIXME: dup the error and call yajl_free_error?
130
+ error = ::FFI_Yajl.yajl_get_error(yajl_handle, 1, str, str.bytesize)
131
+ raise ::FFI_Yajl::ParseError.new(error)
132
+ end
133
+ if ( stat = FFI_Yajl.yajl_complete_parse(yajl_handle) != :yajl_status_ok )
134
+ # FIXME: dup the error and call yajl_free_error?
135
+ error = ::FFI_Yajl.yajl_get_error(yajl_handle, 1, str, str.bytesize)
136
+ raise ::FFI_Yajl::ParseError.new(error)
137
+ end
138
+ finished
139
+ ensure
140
+ ::FFI_Yajl.yajl_free(yajl_handle) if yajl_handle
141
+ end
142
+ end
143
+ end
144
+ end
145
+