Merge branch 'map_support_on_json_parsing' of git://github.com/TheProductWorks/mochiweb into TheProductWorks-map_support_on_json_parsing
diff --git a/rebar.config b/rebar.config
index 59304f5..492832e 100644
--- a/rebar.config
+++ b/rebar.config
@@ -2,7 +2,8 @@
 {erl_opts, [debug_info,
             {platform_define, "R15", 'gen_tcp_r15b_workaround'},
             {platform_define, "(R14|R15|R16B-)", 'crypto_compatibility'},
-            {platform_define, "(R14|R15|R16B|17)", 'rand_mod_unavailable'}]}.
+            {platform_define, "(R14|R15|R16B|17)", 'rand_mod_unavailable'},
+            {platform_define, "(17|18|19)", 'map_available'}]}.
 {cover_enabled, true}.
 {eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}.
 {dialyzer_opts, [{warnings, [no_return,
diff --git a/src/mochijson2.erl b/src/mochijson2.erl
index 255398d..7c63777 100644
--- a/src/mochijson2.erl
+++ b/src/mochijson2.erl
@@ -149,6 +149,43 @@
   when Format =:= struct orelse Format =:= eep18 orelse Format =:= proplist ->
     parse_decoder_options(Rest, State#decoder{object_hook=Format}).
 
+
+-ifdef(map_available).
+json_encode(true, _State) ->
+    <<"true">>;
+json_encode(false, _State) ->
+    <<"false">>;
+json_encode(null, _State) ->
+    <<"null">>;
+json_encode(I, _State) when is_integer(I) ->
+    integer_to_list(I);
+json_encode(F, _State) when is_float(F) ->
+    mochinum:digits(F);
+json_encode(S, State) when is_binary(S); is_atom(S) ->
+    json_encode_string(S, State);
+json_encode([{K, _}|_] = Props, State) when (K =/= struct andalso
+                                             K =/= array andalso
+                                             K =/= json) ->
+    json_encode_proplist(Props, State);
+json_encode({struct, Props}, State) when is_list(Props) ->
+    json_encode_proplist(Props, State);
+json_encode({Props}, State) when is_list(Props) ->
+    json_encode_proplist(Props, State);
+json_encode({}, State) ->
+    json_encode_proplist([], State);
+json_encode(Array, State) when is_list(Array) ->
+    json_encode_array(Array, State);
+json_encode({array, Array}, State) when is_list(Array) ->
+    json_encode_array(Array, State);
+json_encode(M, State) when is_map(M) ->
+    json_encode_map(M, State);
+json_encode({json, IoList}, _State) ->
+    IoList;
+json_encode(Bad, #encoder{handler=null}) ->
+    exit({json_encode, {bad_term, Bad}});
+json_encode(Bad, State=#encoder{handler=Handler}) ->
+    json_encode(Handler(Bad), State).
+-else.
 json_encode(true, _State) ->
     <<"true">>;
 json_encode(false, _State) ->
@@ -181,6 +218,7 @@
     exit({json_encode, {bad_term, Bad}});
 json_encode(Bad, State=#encoder{handler=Handler}) ->
     json_encode(Handler(Bad), State).
+-endif.
 
 json_encode_array([], _State) ->
     <<"[]">>;
@@ -202,6 +240,19 @@
     [$, | Acc1] = lists:foldl(F, "{", Props),
     lists:reverse([$\} | Acc1]).
 
+-ifdef(map_available).
+json_encode_map(Map, _State) when map_size(Map) =:= 0 ->
+    <<"{}">>;
+json_encode_map(Map, State) ->
+    F = fun(K, V, Acc) ->
+                KS = json_encode_string(K, State),
+                VS = json_encode(V, State),
+                [$,, VS, $:, KS | Acc]
+          end,
+    [$, | Acc1] = maps:fold(F, "{", Map),
+    lists:reverse([$\} | Acc1]).
+-endif.
+
 json_encode_string(A, State) when is_atom(A) ->
     json_encode_string(atom_to_binary(A, latin1), State);
 json_encode_string(B, State) when is_binary(B) ->
@@ -939,4 +990,14 @@
     [{"roundtrip escaped", ?_assertEqual(S, decode(encode(S)))},
      {"roundtrip utf8", ?_assertEqual(S, decode((encoder([{utf8, true}]))(S)))}].
 
+% iolist_to_binary(mochijson2:encode(#{a => 1, b => #{ c => 2}})).
+-ifdef(map_available).
+encode_map_test() ->
+    M = <<"{\"a\":1,\"b\":{\"c\":2}}">>,
+    ?assertEqual(M, iolist_to_binary(encode(#{a => 1, b => #{ c => 2}}))).
+encode_empty_map_test() ->
+    ?assertEqual(<<"{}">>, encode(#{})).
+
+-endif.
+
 -endif.