summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ffi_yajl.rb58
-rw-r--r--lib/ffi_yajl/ffi/encoder.rb57
-rw-r--r--spec/ffi_yajl/json_gem_spec.rb1
3 files changed, 82 insertions, 34 deletions
diff --git a/lib/ffi_yajl.rb b/lib/ffi_yajl.rb
index 40c26e4..05090d7 100644
--- a/lib/ffi_yajl.rb
+++ b/lib/ffi_yajl.rb
@@ -30,6 +30,25 @@ module FFI_Yajl
@opts = opts
end
+ def self.raise_error_for_status(status)
+ case status
+ when 1 # yajl_gen_keys_must_be_strings
+ raise FFI_Yajl::EncodeError, "YAJL internal error: attempted use of non-string object as key"
+ when 2 # yajl_max_depth_exceeded
+ raise FFI_Yajl::EncodeError, "Max nesting depth exceeded"
+ when 3 # yajl_gen_in_error_state
+ raise FFI_Yajl::EncodeError, "YAJL internal error: a generator function (yajl_gen_XXX) was called while in an error state"
+ when 4 # yajl_gen_generation_complete
+ raise FFI_Yajl::EncodeError, "YAJL internal error: attempted to encode to an already-complete document"
+ when 5 # yajl_gen_invalid_number
+ raise FFI_Yajl::EncodeError, "Invalid number: cannot encode Infinity, -Infinity, or NaN"
+ when 6 # yajl_gen_no_buf
+ raise FFI_Yajl::EncodeError, "YAJL internal error: yajl_gen_get_buf was called, but a print callback was specified, so no internal buffer is available"
+ else
+ raise FFI_Yajl::EncodeError, "Unknown YAJL Error, please report this as a bug"
+ end
+ end
+
if ENV['FORCE_FFI_YAJL'] == "ext"
require 'ffi_yajl/ext'
include FFI_Yajl::Ext::Encoder
@@ -86,15 +105,15 @@ module FFI_Yajl
:yajl_status_error,
]
- enum :yajl_gen_status, [
- :yajl_gen_status_ok,
- :yajl_gen_keys_must_be_strings,
- :yajl_max_depth_exceeded,
- :yajl_gen_in_error_state,
- :yajl_gen_generation_complete,
- :yajl_gen_invalid_number,
- :yajl_gen_no_buf,
- ]
+# enum :yajl_gen_status, [
+# :yajl_gen_status_ok,
+# :yajl_gen_keys_must_be_strings,
+# :yajl_max_depth_exceeded,
+# :yajl_gen_in_error_state,
+# :yajl_gen_generation_complete,
+# :yajl_gen_invalid_number,
+# :yajl_gen_no_buf,
+# ]
enum :yajl_option, [
:yajl_allow_comments, 0x01,
@@ -145,18 +164,19 @@ module FFI_Yajl
# void yajl_gen_free (yajl_gen handle)
attach_function :yajl_gen_free, [:yajl_gen], :void
- attach_function :yajl_gen_integer, [:yajl_gen, :long_long], :yajl_gen_status
- attach_function :yajl_gen_double, [:yajl_gen, :double], :yajl_gen_status
- attach_function :yajl_gen_number, [:yajl_gen, :ustring, :int], :yajl_gen_status
+ # FFI::Enums are slower than :ints
+ attach_function :yajl_gen_integer, [:yajl_gen, :long_long], :int
+ attach_function :yajl_gen_double, [:yajl_gen, :double], :int
+ attach_function :yajl_gen_number, [:yajl_gen, :ustring, :int], :int
attach_function :yajl_gen_string, [:yajl_gen, :ustring, :int], :int # XXX: FFI Enums are slow?
- attach_function :yajl_gen_null, [:yajl_gen], :yajl_gen_status
- attach_function :yajl_gen_bool, [:yajl_gen, :int], :yajl_gen_status
- attach_function :yajl_gen_map_open, [:yajl_gen], :yajl_gen_status
- attach_function :yajl_gen_map_close, [:yajl_gen], :yajl_gen_status
- attach_function :yajl_gen_array_open, [:yajl_gen], :yajl_gen_status
- attach_function :yajl_gen_array_close, [:yajl_gen], :yajl_gen_status
+ attach_function :yajl_gen_null, [:yajl_gen], :int
+ attach_function :yajl_gen_bool, [:yajl_gen, :int], :int
+ attach_function :yajl_gen_map_open, [:yajl_gen], :int
+ attach_function :yajl_gen_map_close, [:yajl_gen], :int
+ attach_function :yajl_gen_array_open, [:yajl_gen], :int
+ attach_function :yajl_gen_array_close, [:yajl_gen], :int
# yajl_gen_status yajl_gen_get_buf (yajl_gen hand, const unsigned char **buf, unsigned int *len)
- attach_function :yajl_gen_get_buf, [:yajl_gen, :pointer ,:pointer], :yajl_gen_status
+ attach_function :yajl_gen_get_buf, [:yajl_gen, :pointer ,:pointer], :int
# void yajl_gen_clear (yajl_gen hand)
attach_function :yajl_gen_clear, [:yajl_gen], :void
diff --git a/lib/ffi_yajl/ffi/encoder.rb b/lib/ffi_yajl/ffi/encoder.rb
index 42725b0..058fc2b 100644
--- a/lib/ffi_yajl/ffi/encoder.rb
+++ b/lib/ffi_yajl/ffi/encoder.rb
@@ -31,7 +31,9 @@ module FFI_Yajl
# get back our encoded JSON
string_ptr = ::FFI::MemoryPointer.new(:string)
length_ptr = ::FFI::MemoryPointer.new(:int)
- FFI_Yajl.yajl_gen_get_buf(yajl_gen, string_ptr, length_ptr)
+ if ( status = FFI_Yajl.yajl_gen_get_buf(yajl_gen, string_ptr, length_ptr) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
length = length_ptr.read_int
string = string_ptr.get_pointer(0).read_string
@@ -39,13 +41,16 @@ module FFI_Yajl
return string
end
+
end
end
end
class Hash
def ffi_yajl(yajl_gen, state)
- FFI_Yajl.yajl_gen_map_open(yajl_gen)
+ if ( status = FFI_Yajl.yajl_gen_map_open(yajl_gen) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
self.each do |key, value|
# Perf Fix: mutate state hash rather than creating new copy
state[:processing_key] = true
@@ -53,35 +58,47 @@ class Hash
state[:processing_key] = false
value.ffi_yajl(yajl_gen, state)
end
- FFI_Yajl.yajl_gen_map_close(yajl_gen)
+ if ( status = FFI_Yajl.yajl_gen_map_close(yajl_gen) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
class Array
def ffi_yajl(yajl_gen, state)
- FFI_Yajl.yajl_gen_array_open(yajl_gen)
+ if ( status = FFI_Yajl.yajl_gen_array_open(yajl_gen) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
self.each do |value|
value.ffi_yajl(yajl_gen, state)
end
- FFI_Yajl.yajl_gen_array_close(yajl_gen)
+ if ( status = FFI_Yajl.yajl_gen_array_close(yajl_gen) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
class NilClass
def ffi_yajl(yajl_gen, state)
- FFI_Yajl.yajl_gen_null(yajl_gen)
+ if ( status = FFI_Yajl.yajl_gen_null(yajl_gen) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
class TrueClass
def ffi_yajl(yajl_gen, state)
- FFI_Yajl.yajl_gen_bool(yajl_gen, 0)
+ if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 0) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
class FalseClass
def ffi_yajl(yajl_gen, state)
- FFI_Yajl.yajl_gen_bool(yajl_gen, 1)
+ if ( status = FFI_Yajl.yajl_gen_bool(yajl_gen, 1) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
@@ -89,9 +106,13 @@ class Fixnum
def ffi_yajl(yajl_gen, state)
if state[:processing_key]
str = self.to_s
- FFI_Yajl.yajl_gen_string(yajl_gen, str, str.length)
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.length) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
else
- FFI_Yajl.yajl_gen_integer(yajl_gen, self)
+ if ( status = FFI_Yajl.yajl_gen_integer(yajl_gen, self) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
end
@@ -99,19 +120,25 @@ end
class Bignum
def ffi_yajl(yajl_gen, state)
str = self.to_s
- FFI_Yajl.yajl_gen_number(yajl_gen, str, str.length)
+ if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, str, str.length) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
class Float
def ffi_yajl(yajl_gen, state)
- FFI_Yajl.yajl_gen_double(yajl_gen, self)
+ if ( status = FFI_Yajl.yajl_gen_double(yajl_gen, self) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
class String
def ffi_yajl(yajl_gen, state)
- FFI_Yajl.yajl_gen_string(yajl_gen, self, self.length)
+ if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, self, self.length) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
@@ -125,7 +152,9 @@ class Object
def ffi_yajl(yajl_gen, state)
json = self.to_json(state[:json_opts])
- FFI_Yajl.yajl_gen_number(yajl_gen, json, json.length)
+ if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, json, json.length) ) != 0
+ FFI_Yajl::Encoder.raise_error_for_status(status)
+ end
end
end
diff --git a/spec/ffi_yajl/json_gem_spec.rb b/spec/ffi_yajl/json_gem_spec.rb
index 1b614e4..d28f9f6 100644
--- a/spec/ffi_yajl/json_gem_spec.rb
+++ b/spec/ffi_yajl/json_gem_spec.rb
@@ -164,7 +164,6 @@ describe "JSON Gem Compat API" do
expect{ JSON.parse("blah") }.to raise_error(JSON::ParserError)
end
it "should raise JSON::GeneratorError on encoding NaN" do
- pending("fix NaN encoding issue")
expect{ JSON.generate(0.0/0.0) }.to raise_error(JSON::GeneratorError)
end
it "should raise JSON::GeneratorError on encoding a partial UTF-8 character" do