You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
18 KiB
344 lines
18 KiB
#Region "Microsoft.VisualBasic::370b5a447c484484e508d32e2bf75164, Google.Protobuf\FieldCodec.vb"
|
|
|
|
' Author:
|
|
'
|
|
' asuka (amethyst.asuka@gcmodeller.org)
|
|
' xie (genetics@smrucc.org)
|
|
' xieguigang (xie.guigang@live.com)
|
|
'
|
|
' Copyright (c) 2018 GPL3 Licensed
|
|
'
|
|
'
|
|
' GNU GENERAL PUBLIC LICENSE (GPL3)
|
|
'
|
|
'
|
|
' This program is free software: you can redistribute it and/or modify
|
|
' it under the terms of the GNU General Public License as published by
|
|
' the Free Software Foundation, either version 3 of the License, or
|
|
' (at your option) any later version.
|
|
'
|
|
' This program is distributed in the hope that it will be useful,
|
|
' but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
' GNU General Public License for more details.
|
|
'
|
|
' You should have received a copy of the GNU General Public License
|
|
' along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
' /********************************************************************************/
|
|
|
|
' Summaries:
|
|
|
|
' Module FieldCodec
|
|
'
|
|
' Function: ForBool, ForBytes, ForClassWrapper, ForDouble, ForEnum
|
|
' ForFixed32, ForFixed64, ForFloat, ForInt32, ForInt64
|
|
' ForMessage, ForSFixed32, ForSFixed64, ForSInt32, ForSInt64
|
|
' ForString, ForStructWrapper, ForUInt32, ForUInt64
|
|
' Class WrapperCodecs
|
|
'
|
|
' Function: CalculateSize, GetCodec, Read
|
|
'
|
|
' Sub: Write
|
|
'
|
|
'
|
|
'
|
|
'
|
|
' /********************************************************************************/
|
|
|
|
#End Region
|
|
|
|
#Region "Copyright notice and license"
|
|
' Protocol Buffers - Google's data interchange format
|
|
' Copyright 2015 Google Inc. All rights reserved.
|
|
' https://developers.google.com/protocol-buffers/
|
|
'
|
|
' Redistribution and use in source and binary forms, with or without
|
|
' modification, are permitted provided that the following conditions are
|
|
' met:
|
|
'
|
|
' * Redistributions of source code must retain the above copyright
|
|
' notice, this list of conditions and the following disclaimer.
|
|
' * Redistributions in binary form must reproduce the above
|
|
' copyright notice, this list of conditions and the following disclaimer
|
|
' in the documentation and/or other materials provided with the
|
|
' distribution.
|
|
' * Neither the name of Google Inc. nor the names of its
|
|
' contributors may be used to endorse or promote products derived from
|
|
' this software without specific prior written permission.
|
|
'
|
|
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#End Region
|
|
|
|
Imports Google.Protobuf.WellKnownTypes
|
|
Imports Microsoft.VisualBasic.Language
|
|
Imports System
|
|
Imports System.Collections.Generic
|
|
|
|
Namespace Google.Protobuf
|
|
''' <summary>
|
|
''' Factory methods for <see cref="FieldCodecType(OfT)"/>.
|
|
''' </summary>
|
|
Public Module FieldCodec
|
|
' TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a string field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForString(tag As UInteger) As FieldCodecType(Of String)
|
|
Return New FieldCodecType(Of String)(Function(input) input.ReadString(), Sub(output, value) output.WriteString(value), AddressOf CodedOutputStream.ComputeStringSize, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a bytes field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForBytes(tag As UInteger) As FieldCodecType(Of ByteString)
|
|
Return New FieldCodecType(Of ByteString)(Function(input) input.ReadBytes(), Sub(output, value) output.WriteBytes(value), AddressOf CodedOutputStream.ComputeBytesSize, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a bool field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForBool(tag As UInteger) As FieldCodecType(Of Boolean)
|
|
Return New FieldCodecType(Of Boolean)(Function(input) input.ReadBool(), Sub(output, value) output.WriteBool(value), AddressOf CodedOutputStream.ComputeBoolSize, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for an int32 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForInt32(tag As UInteger) As FieldCodecType(Of Integer)
|
|
Return New FieldCodecType(Of Integer)(Function(input) input.ReadInt32(), Sub(output, value) output.WriteInt32(value), AddressOf CodedOutputStream.ComputeInt32Size, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for an sint32 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForSInt32(tag As UInteger) As FieldCodecType(Of Integer)
|
|
Return New FieldCodecType(Of Integer)(Function(input) input.ReadSInt32(), Sub(output, value) output.WriteSInt32(value), AddressOf CodedOutputStream.ComputeSInt32Size, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a fixed32 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForFixed32(tag As UInteger) As FieldCodecType(Of UInteger)
|
|
Return New FieldCodecType(Of UInteger)(Function(input) input.ReadFixed32(), Sub(output, value) output.WriteFixed32(value), 4, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for an sfixed32 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForSFixed32(tag As UInteger) As FieldCodecType(Of Integer)
|
|
Return New FieldCodecType(Of Integer)(Function(input) input.ReadSFixed32(), Sub(output, value) output.WriteSFixed32(value), 4, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a uint32 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForUInt32(tag As UInteger) As FieldCodecType(Of UInteger)
|
|
Return New FieldCodecType(Of UInteger)(Function(input) input.ReadUInt32(), Sub(output, value) output.WriteUInt32(value), AddressOf CodedOutputStream.ComputeUInt32Size, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for an int64 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForInt64(tag As UInteger) As FieldCodecType(Of Long)
|
|
Return New FieldCodecType(Of Long)(Function(input) input.ReadInt64(), Sub(output, value) output.WriteInt64(value), AddressOf CodedOutputStream.ComputeInt64Size, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for an sint64 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForSInt64(tag As UInteger) As FieldCodecType(Of Long)
|
|
Return New FieldCodecType(Of Long)(Function(input) input.ReadSInt64(), Sub(output, value) output.WriteSInt64(value), AddressOf CodedOutputStream.ComputeSInt64Size, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a fixed64 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForFixed64(tag As UInteger) As FieldCodecType(Of ULong)
|
|
Return New FieldCodecType(Of ULong)(Function(input) input.ReadFixed64(), Sub(output, value) output.WriteFixed64(value), 8, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for an sfixed64 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForSFixed64(tag As UInteger) As FieldCodecType(Of Long)
|
|
Return New FieldCodecType(Of Long)(Function(input) input.ReadSFixed64(), Sub(output, value) output.WriteSFixed64(value), 8, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a uint64 field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForUInt64(tag As UInteger) As FieldCodecType(Of ULong)
|
|
Return New FieldCodecType(Of ULong)(Function(input) input.ReadUInt64(), Sub(output, value) output.WriteUInt64(value), AddressOf CodedOutputStream.ComputeUInt64Size, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a float field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForFloat(tag As UInteger) As FieldCodecType(Of Single)
|
|
Return New FieldCodecType(Of Single)(Function(input) input.ReadFloat(), Sub(output, value) output.WriteFloat(value), AddressOf CodedOutputStream.ComputeFloatSize, tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a double field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForDouble(tag As UInteger) As FieldCodecType(Of Double)
|
|
Return New FieldCodecType(Of Double)(Function(input) input.ReadDouble(), Sub(output, value) output.WriteDouble(value), AddressOf CodedOutputStream.ComputeDoubleSize, tag)
|
|
End Function
|
|
|
|
' Enums are tricky. We can probably use expression trees to build these delegates automatically,
|
|
' but it's easy to generate the code for it.
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for an enum field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
|
|
''' <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForEnum(Of T)(tag As UInteger, toInt32 As Func(Of T, Integer), fromInt32 As Func(Of Integer, T)) As FieldCodecType(Of T)
|
|
Return New FieldCodecType(Of T)(Function(input) fromInt32(input.ReadEnum()), Sub(output, value) output.WriteEnum(toInt32(value)), Function(value) CodedOutputStream.ComputeEnumSize(toInt32(value)), tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Retrieves a codec suitable for a message field with the given tag.
|
|
''' </summary>
|
|
''' <param name="tag">The tag.</param>
|
|
''' <param name="parser">A parser to use for the message type.</param>
|
|
''' <returns>A codec for the given tag.</returns>
|
|
Public Function ForMessage(Of T As IMessageType(Of T))(tag As UInteger, parser As MessageParserType(Of T)) As FieldCodecType(Of T)
|
|
Return New FieldCodecType(Of T)(Function(input)
|
|
Dim message As T = parser.CreateTemplate()
|
|
input.ReadMessage(message)
|
|
Return message
|
|
End Function, Sub(output, value) output.WriteMessage(value), Function(message) CodedOutputStream.ComputeMessageSize(message), tag)
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Creates a codec for a wrapper type of a class - which must be string or ByteString.
|
|
''' </summary>
|
|
Public Function ForClassWrapper(Of T As Class)(tag As UInteger) As FieldCodecType(Of T)
|
|
Dim nestedCodec = WrapperCodecs.GetCodec(Of T)()
|
|
Return New FieldCodecType(Of T)(Function(input) WrapperCodecs.Read(input, nestedCodec), Sub(output, value) WrapperCodecs.Write(output, value, nestedCodec), Function(value) WrapperCodecs.CalculateSize(value, nestedCodec), tag, Nothing) ' Default value for the wrapper
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Creates a codec for a wrapper type of a struct - which must be Int32, Int64, UInt32, UInt64,
|
|
''' Bool, Single or Double.
|
|
''' </summary>
|
|
Public Function ForStructWrapper(Of T As Structure)(tag As UInteger) As FieldCodecType(Of T?)
|
|
Dim nestedCodec = WrapperCodecs.GetCodec(Of T)()
|
|
Return New FieldCodecType(Of T?)(Function(input) WrapperCodecs.Read(input, nestedCodec), Sub(output, value) WrapperCodecs.Write(output, value.Value, nestedCodec), Function(value) If(value Is Nothing, 0, WrapperCodecs.CalculateSize(value.Value, nestedCodec)), tag, Nothing) ' Default value for the wrapper
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Helper code to create codecs for wrapper types.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' Somewhat ugly with all the static methods, but the conversions involved to/from nullable types make it
|
|
''' slightly tricky to improve. So long as we keep the public API (ForClassWrapper, ForStructWrapper) in place,
|
|
''' we can refactor later if we come up with something cleaner.
|
|
''' </remarks>
|
|
Private NotInheritable Class WrapperCodecs
|
|
Private Shared ReadOnly Codecs As Dictionary(Of System.Type, Object) = New Dictionary(Of System.Type, Object) From {
|
|
{GetType(Boolean), ForBool(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
|
|
{GetType(Integer), ForInt32(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
|
|
{GetType(Long), ForInt64(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
|
|
{GetType(UInteger), ForUInt32(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
|
|
{GetType(ULong), ForUInt64(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
|
|
{GetType(Single), ForFloat(MakeTag(WrapperValueFieldNumber, WireType.Fixed32))},
|
|
{GetType(Double), ForDouble(MakeTag(WrapperValueFieldNumber, WireType.Fixed64))},
|
|
{GetType(String), ForString(MakeTag(WrapperValueFieldNumber, WireType.LengthDelimited))},
|
|
{GetType(ByteString), ForBytes(MakeTag(WrapperValueFieldNumber, WireType.LengthDelimited))}
|
|
}
|
|
|
|
''' <summary>
|
|
''' Returns a field codec which effectively wraps a value of type T in a message.
|
|
'''
|
|
''' </summary>
|
|
Friend Shared Function GetCodec(Of T)() As FieldCodecType(Of T)
|
|
Dim value As Object
|
|
|
|
If Not Codecs.TryGetValue(GetType(T), value) Then
|
|
Throw New InvalidOperationException("Invalid type argument requested for wrapper codec: " & GetType(T).ToString)
|
|
End If
|
|
|
|
Return CType(value, FieldCodecType(Of T))
|
|
End Function
|
|
|
|
Friend Shared Function Read(Of T)(input As CodedInputStream, codec As FieldCodecType(Of T)) As T
|
|
Dim length As Integer = input.ReadLength()
|
|
Dim oldLimit = input.PushLimit(length)
|
|
Dim tag As New Value(Of UInteger)
|
|
Dim value = codec.DefaultValue
|
|
|
|
While (tag = input.ReadTag()) <> 0
|
|
|
|
If tag.Value = codec.Tag Then
|
|
value = codec.Read(input)
|
|
Else
|
|
input.SkipLastField()
|
|
End If
|
|
End While
|
|
|
|
input.CheckReadEndOfStreamTag()
|
|
input.PopLimit(oldLimit)
|
|
Return value
|
|
End Function
|
|
|
|
Friend Shared Sub Write(Of T)(output As CodedOutputStream, value As T, codec As FieldCodecType(Of T))
|
|
output.WriteLength(codec.CalculateSizeWithTag(value))
|
|
codec.WriteTagAndValue(output, value)
|
|
End Sub
|
|
|
|
Friend Shared Function CalculateSize(Of T)(value As T, codec As FieldCodecType(Of T)) As Integer
|
|
Dim fieldLength = codec.CalculateSizeWithTag(value)
|
|
Return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldLength
|
|
End Function
|
|
End Class
|
|
End Module
|
|
End Namespace
|