474 lines
15 KiB
Lua
474 lines
15 KiB
Lua
--
|
|
--------------------------------------------------------------------------------
|
|
-- FILE: encoder.lua
|
|
-- DESCRIPTION: protoc-gen-lua
|
|
-- Google's Protocol Buffers project, ported to lua.
|
|
-- https://code.google.com/p/protoc-gen-lua/
|
|
--
|
|
-- Copyright (c) 2010 , 林卓毅 (Zhuoyi Lin) netsnail@gmail.com
|
|
-- All rights reserved.
|
|
--
|
|
-- Use, modification and distribution are subject to the "New BSD License"
|
|
-- as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
|
|
--
|
|
-- COMPANY: NetEase
|
|
-- CREATED: 2010年07月29日 19时30分46秒 CST
|
|
--------------------------------------------------------------------------------
|
|
--
|
|
local string = string
|
|
local table = table
|
|
local ipairs = ipairs
|
|
local assert =assert
|
|
|
|
local pb = require "pb"
|
|
local wire_format = require "protobuf.wire_format"
|
|
module "protobuf.encoder"
|
|
|
|
function _VarintSize(value)
|
|
if value <= 0x7f then return 1 end
|
|
if value <= 0x3fff then return 2 end
|
|
if value <= 0x1fffff then return 3 end
|
|
if value <= 0xfffffff then return 4 end
|
|
if value <= 0x7ffffffff then return 5 end
|
|
if value <= 0x3ffffffffff then return 6 end
|
|
if value <= 0x1ffffffffffff then return 7 end
|
|
if value <= 0xffffffffffffff then return 8 end
|
|
if value <= 0x7fffffffffffffff then return 9 end
|
|
return 10
|
|
end
|
|
|
|
function _SignedVarintSize(value)
|
|
if value < 0 then return 10 end
|
|
if value <= 0x7f then return 1 end
|
|
if value <= 0x3fff then return 2 end
|
|
if value <= 0x1fffff then return 3 end
|
|
if value <= 0xfffffff then return 4 end
|
|
if value <= 0x7ffffffff then return 5 end
|
|
if value <= 0x3ffffffffff then return 6 end
|
|
if value <= 0x1ffffffffffff then return 7 end
|
|
if value <= 0xffffffffffffff then return 8 end
|
|
if value <= 0x7fffffffffffffff then return 9 end
|
|
return 10
|
|
end
|
|
|
|
function _TagSize(field_number)
|
|
return _VarintSize(wire_format.PackTag(field_number, 0))
|
|
end
|
|
|
|
function _SimpleSizer(compute_value_size)
|
|
return function(field_number, is_repeated, is_packed)
|
|
local tag_size = _TagSize(field_number)
|
|
if is_packed then
|
|
local VarintSize = _VarintSize
|
|
return function(value)
|
|
local result = 0
|
|
for _, element in ipairs(value) do
|
|
result = result + compute_value_size(element)
|
|
end
|
|
return result + VarintSize(result) + tag_size
|
|
end
|
|
elseif is_repeated then
|
|
return function(value)
|
|
local result = tag_size * #value
|
|
for _, element in ipairs(value) do
|
|
result = result + compute_value_size(element)
|
|
end
|
|
return result
|
|
end
|
|
else
|
|
return function (value)
|
|
return tag_size + compute_value_size(value)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _ModifiedSizer(compute_value_size, modify_value)
|
|
return function (field_number, is_repeated, is_packed)
|
|
local tag_size = _TagSize(field_number)
|
|
if is_packed then
|
|
local VarintSize = _VarintSize
|
|
return function (value)
|
|
local result = 0
|
|
for _, element in ipairs(value) do
|
|
result = result + compute_value_size(modify_value(element))
|
|
end
|
|
return result + VarintSize(result) + tag_size
|
|
end
|
|
elseif is_repeated then
|
|
return function (value)
|
|
local result = tag_size * #value
|
|
for _, element in ipairs(value) do
|
|
result = result + compute_value_size(modify_value(element))
|
|
end
|
|
return result
|
|
end
|
|
else
|
|
return function (value)
|
|
return tag_size + compute_value_size(modify_value(value))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _FixedSizer(value_size)
|
|
return function (field_number, is_repeated, is_packed)
|
|
local tag_size = _TagSize(field_number)
|
|
if is_packed then
|
|
local VarintSize = _VarintSize
|
|
return function (value)
|
|
local result = #value * value_size
|
|
return result + VarintSize(result) + tag_size
|
|
end
|
|
elseif is_repeated then
|
|
local element_size = value_size + tag_size
|
|
return function(value)
|
|
return #value * element_size
|
|
end
|
|
else
|
|
local field_size = value_size + tag_size
|
|
return function (value)
|
|
return field_size
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
Int32Sizer = _SimpleSizer(_SignedVarintSize)
|
|
Int64Sizer = _SimpleSizer(pb.signed_varint_size)
|
|
EnumSizer = Int32Sizer
|
|
|
|
UInt32Sizer = _SimpleSizer(_VarintSize)
|
|
UInt64Sizer = _SimpleSizer(pb.varint_size)
|
|
|
|
SInt32Sizer = _ModifiedSizer(_SignedVarintSize, wire_format.ZigZagEncode32)
|
|
SInt64Sizer = SInt32Sizer
|
|
|
|
Fixed32Sizer = _FixedSizer(4)
|
|
SFixed32Sizer = Fixed32Sizer
|
|
FloatSizer = Fixed32Sizer
|
|
|
|
Fixed64Sizer = _FixedSizer(8)
|
|
SFixed64Sizer = Fixed64Sizer
|
|
DoubleSizer = Fixed64Sizer
|
|
|
|
BoolSizer = _FixedSizer(1)
|
|
|
|
|
|
function StringSizer(field_number, is_repeated, is_packed)
|
|
local tag_size = _TagSize(field_number)
|
|
local VarintSize = _VarintSize
|
|
assert(not is_packed)
|
|
if is_repeated then
|
|
return function(value)
|
|
local result = tag_size * #value
|
|
for _, element in ipairs(value) do
|
|
local l = #element
|
|
result = result + VarintSize(l) + l
|
|
end
|
|
return result
|
|
end
|
|
else
|
|
return function(value)
|
|
local l = #value
|
|
return tag_size + VarintSize(l) + l
|
|
end
|
|
end
|
|
end
|
|
|
|
function BytesSizer(field_number, is_repeated, is_packed)
|
|
local tag_size = _TagSize(field_number)
|
|
local VarintSize = _VarintSize
|
|
assert(not is_packed)
|
|
if is_repeated then
|
|
return function (value)
|
|
local result = tag_size * #value
|
|
for _,element in ipairs(value) do
|
|
local l = #element
|
|
result = result + VarintSize(l) + l
|
|
end
|
|
return result
|
|
end
|
|
else
|
|
return function (value)
|
|
local l = #value
|
|
return tag_size + VarintSize(l) + l
|
|
end
|
|
end
|
|
end
|
|
|
|
function MessageSizer(field_number, is_repeated, is_packed)
|
|
local tag_size = _TagSize(field_number)
|
|
local VarintSize = _VarintSize
|
|
assert(not is_packed)
|
|
if is_repeated then
|
|
return function(value)
|
|
local result = tag_size * #value
|
|
for _,element in ipairs(value) do
|
|
local l = element:ByteSize()
|
|
result = result + VarintSize(l) + l
|
|
end
|
|
return result
|
|
end
|
|
else
|
|
return function (value)
|
|
local l = value:ByteSize()
|
|
return tag_size + VarintSize(l) + l
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- ====================================================================
|
|
-- Encoders!
|
|
|
|
local _EncodeVarint = pb.varint_encoder
|
|
local _EncodeSignedVarint = pb.signed_varint_encoder
|
|
local _EncodeVarint64 = pb.varint_encoder64
|
|
local _EncodeSignedVarint64 = pb.signed_varint_encoder64
|
|
|
|
|
|
function _VarintBytes(value)
|
|
local out = {}
|
|
local write = function(value)
|
|
out[#out + 1 ] = value
|
|
end
|
|
_EncodeSignedVarint(write, value)
|
|
return table.concat(out)
|
|
end
|
|
|
|
function TagBytes(field_number, wire_type)
|
|
return _VarintBytes(wire_format.PackTag(field_number, wire_type))
|
|
end
|
|
|
|
function _SimpleEncoder(wire_type, encode_value, compute_value_size)
|
|
return function(field_number, is_repeated, is_packed)
|
|
if is_packed then
|
|
local tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
|
local EncodeVarint = _EncodeVarint
|
|
return function(write, value)
|
|
write(tag_bytes)
|
|
local size = 0
|
|
for _, element in ipairs(value) do
|
|
size = size + compute_value_size(element)
|
|
end
|
|
EncodeVarint(write, size)
|
|
for element in value do
|
|
encode_value(write, element)
|
|
end
|
|
end
|
|
elseif is_repeated then
|
|
local tag_bytes = TagBytes(field_number, wire_type)
|
|
return function(write, value)
|
|
for _, element in ipairs(value) do
|
|
write(tag_bytes)
|
|
encode_value(write, element)
|
|
end
|
|
end
|
|
else
|
|
local tag_bytes = TagBytes(field_number, wire_type)
|
|
return function(write, value)
|
|
write(tag_bytes)
|
|
encode_value(write, value)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _ModifiedEncoder(wire_type, encode_value, compute_value_size, modify_value)
|
|
return function (field_number, is_repeated, is_packed)
|
|
if is_packed then
|
|
local tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
|
local EncodeVarint = _EncodeVarint
|
|
return function (write, value)
|
|
write(tag_bytes)
|
|
local size = 0
|
|
for _, element in ipairs(value) do
|
|
size = size + compute_value_size(modify_value(element))
|
|
end
|
|
EncodeVarint(write, size)
|
|
for _, element in ipairs(value) do
|
|
encode_value(write, modify_value(element))
|
|
end
|
|
end
|
|
elseif is_repeated then
|
|
local tag_bytes = TagBytes(field_number, wire_type)
|
|
return function (write, value)
|
|
for _, element in ipairs(value) do
|
|
write(tag_bytes)
|
|
encode_value(write, modify_value(element))
|
|
end
|
|
end
|
|
else
|
|
local tag_bytes = TagBytes(field_number, wire_type)
|
|
return function (write, value)
|
|
write(tag_bytes)
|
|
encode_value(write, modify_value(value))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _StructPackEncoder(wire_type, value_size, format)
|
|
return function(field_number, is_repeated, is_packed)
|
|
local struct_pack = pb.struct_pack
|
|
if is_packed then
|
|
local tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
|
local EncodeVarint = _EncodeVarint
|
|
return function (write, value)
|
|
write(tag_bytes)
|
|
EncodeVarint(write, #value * value_size)
|
|
for _, element in ipairs(value) do
|
|
struct_pack(write, format, element)
|
|
end
|
|
end
|
|
elseif is_repeated then
|
|
local tag_bytes = TagBytes(field_number, wire_type)
|
|
return function (write, value)
|
|
for _, element in ipairs(value) do
|
|
write(tag_bytes)
|
|
struct_pack(write, format, element)
|
|
end
|
|
end
|
|
else
|
|
local tag_bytes = TagBytes(field_number, wire_type)
|
|
return function (write, value)
|
|
write(tag_bytes)
|
|
struct_pack(write, format, value)
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
Int32Encoder = _SimpleEncoder(wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize)
|
|
Int64Encoder = _SimpleEncoder(wire_format.WIRETYPE_VARINT, _EncodeSignedVarint64, _SignedVarintSize)
|
|
EnumEncoder = Int32Encoder
|
|
|
|
UInt32Encoder = _SimpleEncoder(wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize)
|
|
UInt64Encoder = _SimpleEncoder(wire_format.WIRETYPE_VARINT, _EncodeVarint64, _VarintSize)
|
|
|
|
SInt32Encoder = _ModifiedEncoder(
|
|
wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize,
|
|
wire_format.ZigZagEncode32)
|
|
|
|
SInt64Encoder = _ModifiedEncoder(
|
|
wire_format.WIRETYPE_VARINT, _EncodeVarint64, _VarintSize,
|
|
wire_format.ZigZagEncode64)
|
|
|
|
Fixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, 4, string.byte('I'))
|
|
Fixed64Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, 8, string.byte('Q'))
|
|
SFixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, 4, string.byte('i'))
|
|
SFixed64Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, 8, string.byte('q'))
|
|
FloatEncoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, 4, string.byte('f'))
|
|
DoubleEncoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, 8, string.byte('d'))
|
|
|
|
|
|
function BoolEncoder(field_number, is_repeated, is_packed)
|
|
local false_byte = '\0'
|
|
local true_byte = '\1'
|
|
if is_packed then
|
|
local tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
|
local EncodeVarint = _EncodeVarint
|
|
return function (write, value)
|
|
write(tag_bytes)
|
|
EncodeVarint(write, #value)
|
|
for _, element in ipairs(value) do
|
|
if element then
|
|
write(true_byte)
|
|
else
|
|
write(false_byte)
|
|
end
|
|
end
|
|
end
|
|
elseif is_repeated then
|
|
local tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
|
|
return function(write, value)
|
|
for _, element in ipairs(value) do
|
|
write(tag_bytes)
|
|
if element then
|
|
write(true_byte)
|
|
else
|
|
write(false_byte)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
local tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
|
|
return function (write, value)
|
|
write(tag_bytes)
|
|
if value then
|
|
return write(true_byte)
|
|
end
|
|
return write(false_byte)
|
|
end
|
|
end
|
|
end
|
|
|
|
function StringEncoder(field_number, is_repeated, is_packed)
|
|
local tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
|
local EncodeVarint = _EncodeVarint
|
|
assert(not is_packed)
|
|
if is_repeated then
|
|
return function (write, value)
|
|
for _, element in ipairs(value) do
|
|
-- encoded = element.encode('utf-8')
|
|
write(tag)
|
|
EncodeVarint(write, #element)
|
|
write(element)
|
|
end
|
|
end
|
|
else
|
|
return function (write, value)
|
|
-- local encoded = value.encode('utf-8')
|
|
write(tag)
|
|
EncodeVarint(write, #value)
|
|
return write(value)
|
|
end
|
|
end
|
|
end
|
|
|
|
function BytesEncoder(field_number, is_repeated, is_packed)
|
|
local tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
|
local EncodeVarint = _EncodeVarint
|
|
assert(not is_packed)
|
|
if is_repeated then
|
|
return function (write, value)
|
|
for _, element in ipairs(value) do
|
|
write(tag)
|
|
EncodeVarint(write, #element)
|
|
write(element)
|
|
end
|
|
end
|
|
else
|
|
return function(write, value)
|
|
write(tag)
|
|
EncodeVarint(write, #value)
|
|
return write(value)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function MessageEncoder(field_number, is_repeated, is_packed)
|
|
local tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
|
local EncodeVarint = _EncodeVarint
|
|
assert(not is_packed)
|
|
if is_repeated then
|
|
return function(write, value)
|
|
for _, element in ipairs(value) do
|
|
write(tag)
|
|
EncodeVarint(write, element:ByteSize())
|
|
element:_InternalSerialize(write)
|
|
end
|
|
end
|
|
else
|
|
return function (write, value)
|
|
write(tag)
|
|
EncodeVarint(write, value:ByteSize())
|
|
return value:_InternalSerialize(write)
|
|
end
|
|
end
|
|
end
|
|
|