Current section
Files
Jump to
Current section
Files
lib/type/array.ex
defmodule ProtoDef.Type.Array do
alias ProtoDef.Compiler.Preprocess
use ProtoDef.Type
@no_type_error "Array was without type field"
defstruct type: nil, count: nil,
ident: nil, count_ident: nil, child_ident: nil
def preprocess(args, ctx) do
type = args["type"]
if !type do
raise ProtoDef.CompileError, message: @no_type_error
end
%__MODULE__{
type: Preprocess.process_type(type, ctx),
count: Preprocess.process_count(args, ctx),
}
end
def structure(descr, ctx) do
{:array, ProtoDef.Compiler.Structure.gen_for_type(descr.type, ctx)}
end
def assign_vars(descr, num, ctx) do
{child_descr, child_ident, num} =
ProtoDef.Compiler.AssignIdents.assign(descr.type, num, ctx)
{count_descr, count_ident, num} =
ProtoDef.Compiler.AssignIdents.assign_count(descr.count, num, ctx)
{ident, num} = ProtoDef.Compiler.AssignIdents.make_ident(num, ctx)
descr = %{ descr |
ident: ident,
count_ident: count_ident,
count: count_descr,
#count_type: count_descr,
child_ident: child_ident,
type: child_descr,
}
{descr, ident, num}
end
def resolve_references(descr, parents, ctx) do
type = ProtoDef.Compiler.Resolve.run(descr.type, parents, ctx)
count = ProtoDef.Compiler.Resolve.resolve_count(descr.count, parents, ctx)
%{ descr |
type: type,
count: count,
}
end
def decoder_ast(descr, ctx) do
count_ast = ProtoDef.Compiler.Count.decoder_ast(descr.count, ctx)
type_ast = ProtoDef.Compiler.GenAst.decoder(descr.type, ctx)
quote do
with do
{count, unquote(@data_var)} = unquote(count_ast)
{elems, unquote(@data_var)} = Enum.reduce(1..count, {[], unquote(@data_var)}, fn(_, {elems, unquote(@data_var)}) ->
{new_elem, unquote(@data_var)} = unquote(type_ast)
{[new_elem | elems], unquote(@data_var)}
end)
{Enum.reverse(elems), unquote(@data_var)}
end
end
end
def encoder_ast(descr, ctx) do
count_var = Macro.var(:count, ProtoDef.Type.Array)
count_encoder = ProtoDef.Compiler.Count.encoder_ast(descr.count, count_var, ctx)
item_encoder = ProtoDef.Compiler.GenAst.encoder(descr.type, ctx)
quote do
with do
unquote(count_var) = Enum.count(unquote(@input_var))
count_head = unquote(count_encoder)
array_body = Enum.map(unquote(@input_var), fn unquote(@input_var) ->
unquote(item_encoder)
end)
[count_head, array_body]
end
end
end
end
defmodule ProtoDef.Type.ArrayCount do
alias ProtoDef.Compiler.Preprocess
use ProtoDef.Type
defstruct type: nil, count_for_selector: nil, count_for: nil, ident: nil
def preprocess(args, ctx) do
%__MODULE__{
type: Preprocess.process_type(args["type"], ctx),
count_for_selector: Preprocess.process_field_ref(args["countFor"], ctx, true),
}
end
def structure(type, ctx), do: __MODULE__
def assign_vars(descr, num, ctx) do
{type, ident, num} = ProtoDef.Compiler.AssignIdents.assign(descr.type, num, ctx)
descr = %{ descr |
ident: ident,
type: type,
}
{descr, ident, num}
end
def resolve_references(descr, parents, ctx) do
type = ProtoDef.Compiler.Resolve.run(descr.type, parents, ctx)
%{ descr |
type: type,
count_for: ProtoDef.Compiler.Resolve.resolve_parent(descr.count_for_selector, parents, ctx)
}
end
def decoder_ast(descr, ctx) do
ProtoDef.Compiler.GenAst.decoder(descr.type, ctx)
end
def encoder_ast(descr, ctx) do
{count_container_ident, count_field} = descr.count_for
count_container = Macro.var(count_container_ident, nil)
field_encoder = ProtoDef.Compiler.GenAst.encoder(descr.type, ctx)
quote do
with do
len_source = unquote(count_container)[unquote(count_field)]
unquote(@input_var) = Enum.count(len_source)
unquote(field_encoder)
end
end
end
end