@@ -121,8 +121,8 @@ defmodule Protobuf.JSON do
121121 """
122122 @ spec encode! ( struct , [ encode_opt ] ) :: String . t ( ) | no_return
123123 def encode! ( struct , opts \\ [ ] ) do
124- case encode ( struct , opts ) do
125- { :ok , json } -> json
124+ case encode_to_iodata ( struct , opts ) do
125+ { :ok , iodata } -> IO . iodata_to_binary ( iodata )
126126 { :error , error } -> raise error
127127 end
128128 end
@@ -169,9 +169,41 @@ defmodule Protobuf.JSON do
169169 """
170170 @ spec encode ( struct , [ encode_opt ] ) ::
171171 { :ok , String . t ( ) } | { :error , EncodeError . t ( ) | Exception . t ( ) }
172- def encode ( % _ { } = struct , opts \\ [ ] ) when is_list ( opts ) do
172+ def encode ( struct , opts \\ [ ] ) when is_list ( opts ) do
173+ case encode_to_iodata ( struct , opts ) do
174+ { :ok , iodata } -> { :ok , IO . iodata_to_binary ( iodata ) }
175+ { :error , error } -> { :error , error }
176+ end
177+ end
178+
179+ @ doc """
180+ Similar to `encode!/2`, but returns iodata
181+
182+ See `encode_to_iodata/2` for more information about when this function should
183+ be preferred over `encode!/2`.
184+ """
185+ @ spec encode_to_iodata! ( struct , [ encode_opt ] ) :: iodata ( )
186+ def encode_to_iodata! ( struct , opts \\ [ ] ) when is_list ( opts ) do
187+ case encode_to_iodata ( struct , opts ) do
188+ { :ok , iodata } -> iodata
189+ { :error , error } -> raise error
190+ end
191+ end
192+
193+ @ doc """
194+ Similar to `encode/2`, but returns iodata
195+
196+ This function should be preferred to encode/2, if the generated JSON will be
197+ handed over to one of the IO functions or sent over the socket. The Erlang
198+ runtime is able to leverage vectorised writes and avoid allocating a continuous
199+ buffer for the whole resulting string, lowering memory use and increasing
200+ performance.
201+ """
202+ @ spec encode_to_iodata ( struct , [ encode_opt ] ) ::
203+ { :ok , iodata ( ) } | { :error , EncodeError . t ( ) | Exception . t ( ) }
204+ def encode_to_iodata ( % _ { } = struct , opts \\ [ ] ) when is_list ( opts ) do
173205 if jason = load_jason ( ) do
174- with { :ok , map } <- to_encodable ( struct , opts ) , do: jason . encode ( map )
206+ with { :ok , map } <- to_encodable ( struct , opts ) , do: jason . encode_to_iodata ( map )
175207 else
176208 { :error , EncodeError . new ( :no_json_lib ) }
177209 end
0 commit comments