--- JSON-XS/XS.xs 2007/06/23 23:49:29 1.43 +++ JSON-XS/XS.xs 2007/06/25 04:08:17 1.44 @@ -17,23 +17,22 @@ # define UTF8_MAXBYTES 13 #endif -#define F_ASCII 0x00000001UL -#define F_LATIN1 0x00000002UL -#define F_UTF8 0x00000004UL -#define F_INDENT 0x00000008UL -#define F_CANONICAL 0x00000010UL -#define F_SPACE_BEFORE 0x00000020UL -#define F_SPACE_AFTER 0x00000040UL -#define F_ALLOW_NONREF 0x00000100UL -#define F_SHRINK 0x00000200UL -#define F_MAXDEPTH 0xf8000000UL -#define S_MAXDEPTH 27 +#define F_ASCII 0x00000001UL +#define F_LATIN1 0x00000002UL +#define F_UTF8 0x00000004UL +#define F_INDENT 0x00000008UL +#define F_CANONICAL 0x00000010UL +#define F_SPACE_BEFORE 0x00000020UL +#define F_SPACE_AFTER 0x00000040UL +#define F_ALLOW_NONREF 0x00000100UL +#define F_SHRINK 0x00000200UL +#define F_ALLOW_BLESSED 0x00000400UL +#define F_CONV_BLESSED 0x00000800UL // NYI +#define F_MAXDEPTH 0xf8000000UL +#define S_MAXDEPTH 27 #define DEC_DEPTH(flags) (1UL << ((flags & F_MAXDEPTH) >> S_MAXDEPTH)) -// F_SELFCONVERT? <=> to_json/toJson -// F_BLESSED? <=> { $__class__$ => } - #define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER #define F_DEFAULT (9UL << S_MAXDEPTH) @@ -56,7 +55,7 @@ #define expect_false(expr) expect ((expr) != 0, 0) #define expect_true(expr) expect ((expr) != 0, 1) -static HV *json_stash; // JSON::XS:: +static HV *json_stash, *json_boolean_stash; // JSON::XS:: static SV *json_true, *json_false; ///////////////////////////////////////////////////////////////////////////// @@ -471,7 +470,61 @@ SvGETMAGIC (sv); svt = SvTYPE (sv); - if (svt == SVt_PVHV) + if (expect_false (SvOBJECT (sv))) + { + if (SvSTASH (sv) == json_boolean_stash) + { + if (SvIV (sv) == 0) + encode_str (enc, "false", 5, 0); + else + encode_str (enc, "true", 4, 0); + } + else + { +#if 0 + if (0 && sv_derived_from (rv, "JSON::Literal")) + { + // not yet + } +#endif + if (enc->flags & F_CONV_BLESSED) + { + // we re-bless the reference to get overload and other niceties right + GV *to_json = gv_fetchmethod_autoload (SvSTASH (sv), "TO_JSON", 1); + + if (to_json) + { + dSP; + ENTER; + SAVETMPS; + PUSHMARK (SP); + XPUSHs (sv_bless (sv_2mortal (newRV_inc (sv)), SvSTASH (sv))); + + // calling with G_SCALAR ensures that we always get a 1 reutrn value + // check anyways. + PUTBACK; + assert (1 == call_sv ((SV *)GvCV (to_json), G_SCALAR)); + SPAGAIN; + + encode_sv (enc, POPs); + + FREETMPS; + LEAVE; + } + else if (enc->flags & F_ALLOW_BLESSED) + encode_str (enc, "null", 4, 0); + else + croak ("encountered object '%s', but neither allow_blessed enabled nor TO_JSON method available on it", + SvPV_nolen (sv_2mortal (newRV_inc (sv)))); + } + else if (enc->flags & F_ALLOW_BLESSED) + encode_str (enc, "null", 4, 0); + else + croak ("encountered object '%s', but neither allow_blessed nor convert_blessed settings are enabled", + SvPV_nolen (sv_2mortal (newRV_inc (sv)))); + } + } + else if (svt == SVt_PVHV) encode_hv (enc, (HV *)sv); else if (svt == SVt_PVAV) encode_av (enc, (AV *)sv); @@ -1165,7 +1218,8 @@ : i >= 'A' && i <= 'F' ? i - 'A' + 10 : -1; - json_stash = gv_stashpv ("JSON::XS", 1); + json_stash = gv_stashpv ("JSON::XS" , 1); + json_boolean_stash = gv_stashpv ("JSON::XS::Boolean", 1); json_true = get_sv ("JSON::XS::true" , 1); SvREADONLY_on (json_true ); json_false = get_sv ("JSON::XS::false", 1); SvREADONLY_on (json_false); @@ -1181,16 +1235,18 @@ SV *ascii (SV *self, int enable = 1) ALIAS: - ascii = F_ASCII - latin1 = F_LATIN1 - utf8 = F_UTF8 - indent = F_INDENT - canonical = F_CANONICAL - space_before = F_SPACE_BEFORE - space_after = F_SPACE_AFTER - pretty = F_PRETTY - allow_nonref = F_ALLOW_NONREF - shrink = F_SHRINK + ascii = F_ASCII + latin1 = F_LATIN1 + utf8 = F_UTF8 + indent = F_INDENT + canonical = F_CANONICAL + space_before = F_SPACE_BEFORE + space_after = F_SPACE_AFTER + pretty = F_PRETTY + allow_nonref = F_ALLOW_NONREF + shrink = F_SHRINK + allow_blessed = F_ALLOW_BLESSED + convert_blessed = F_CONV_BLESSED CODE: { UV *uv = SvJSON (self);