golang protobuf序列化分析

Lynn_Yuan · · 1045 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

  1. data.proto
    message ColumnarValue {
    uint32 id= 1;
    int32 typ = 2;
    repeated bytes values = 3;
    }

    data.go.proto

    type ColumnarValue struct {
    Id   uint32   `protobuf:"varint,1,opt,name=id,json=id,proto3" json:"id,omitempty"`
    Typ int32    `protobuf:"varint,2,opt,name=typ,json=typ,proto3" json:"typ,omitempty"`
    Values  [][]byte `protobuf:"bytes,3,rep,name=values,proto3" json:"values,omitempty"`
    }
  2. 序列化
    func (m *ColumnarValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    b = b[:cap(b)]
    n, err := m.MarshalTo(b)
    if err != nil {
        return nil, err
    }
    return b[:n], nil
    }
func (m *ColumnarValue) MarshalTo(dAtA []byte) (int, error) {
    var i int
    _ = i
    var l int
    _ = l
    if m.Id != 0 {
        dAtA[i] = 0x8
        i++
        i = encodeVarintData(dAtA, i, uint64(m.Id))
    }
    if m.Typ != 0 {
        dAtA[i] = 0x10
        i++
        i = encodeVarintData(dAtA, i, uint64(m.Typ))
    }
    if len(m.Values) > 0 {  // [][]byte序列化
        for _, b := range m.Values {
            dAtA[i] = 0x1a
            i++
            i = encodeVarintData(dAtA, i, uint64(len(b)))  // 对byte Slice的长度(int值)编码
            i += copy(dAtA[i:], b)              // 直接复制b(bytes)切片
        }
    }
    return i, nil
}

编码(slice长度)

func encodeVarintData(dAtA []byte, offset int, v uint64) int {
    for v >= 1<<7 {
        dAtA[offset] = uint8(v&0x7f | 0x80)
        v >>= 7
        offset++
    }
    dAtA[offset] = uint8(v)
    return offset + 1
}
  1. 反序列化

    func (m *VecValue) XXX_Unmarshal(b []byte) error {
    return m.Unmarshal(b)
    }
    func (m *VecValue) Unmarshal(dAtA []byte) error {
    l := len(dAtA)
    iNdEx := 0
    for iNdEx < l {
        preIndex := iNdEx
        var wire uint64
        for shift := uint(0); ; shift += 7 {
            if shift >= 64 {
                return ErrIntOverflowData
            }
            if iNdEx >= l {
                return io.ErrUnexpectedEOF
            }
            b := dAtA[iNdEx]
            iNdEx++
            wire |= (uint64(b) & 0x7F) << shift
            if b < 0x80 {
                break
            }
        }
        fieldNum := int32(wire >> 3)
        wireType := int(wire & 0x7)
        if wireType == 4 {
            return fmt.Errorf("proto: VecValue: wiretype end group for non-group")
        }
        if fieldNum <= 0 {
            return fmt.Errorf("proto: VecValue: illegal tag %d (wire type %d)", fieldNum, wire)
        }
        switch fieldNum {
        case 1:
            if wireType != 0 {
                return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType)
            }
            m.Id = 0
            for shift := uint(0); ; shift += 7 {
                if shift >= 64 {
                    return ErrIntOverflowData
                }
                if iNdEx >= l {
                    return io.ErrUnexpectedEOF
                }
                b := dAtA[iNdEx]
                iNdEx++
                m.Id |= (uint32(b) & 0x7F) << shift
                if b < 0x80 {
                    break
                }
            }
        case 2:
            if wireType != 0 {
                return fmt.Errorf("proto: wrong wireType = %d for field Typ", wireType)
            }
            m.Typ = 0
            for shift := uint(0); ; shift += 7 {
                if shift >= 64 {
                    return ErrIntOverflowData
                }
                if iNdEx >= l {
                    return io.ErrUnexpectedEOF
                }
                b := dAtA[iNdEx]
                iNdEx++
                m.Typ |= (int32(b) & 0x7F) << shift
                if b < 0x80 {
                    break
                }
            }
        case 3:
            if wireType != 2 {
                return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType)
            }
            var byteLen int
            for shift := uint(0); ; shift += 7 {
                if shift >= 64 {
                    return ErrIntOverflowData
                }
                if iNdEx >= l {
                    return io.ErrUnexpectedEOF
                }
                b := dAtA[iNdEx]
                iNdEx++
                byteLen |= (int(b) & 0x7F) << shift
                if b < 0x80 {
                    break
                }
            }
            if byteLen < 0 {
                return ErrInvalidLengthData
            }
            postIndex := iNdEx + byteLen
            if postIndex > l {
                return io.ErrUnexpectedEOF
            }
            m.Values = append(m.Values, make([]byte, postIndex-iNdEx))
            copy(m.Values[len(m.Values)-1], dAtA[iNdEx:postIndex])  // 直接复制dAtA切片中指定内容, go层内部 内存复制
            iNdEx = postIndex
        default:
            iNdEx = preIndex
            skippy, err := skipData(dAtA[iNdEx:])
            if err != nil {
                return err
            }
            if skippy < 0 {
                return ErrInvalidLengthData
            }
            if (iNdEx + skippy) > l {
                return io.ErrUnexpectedEOF
            }
            iNdEx += skippy
        }
    }
    
    if iNdEx > l {
        return io.ErrUnexpectedEOF
    }
    return nil
    }

有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:Lynn_Yuan

查看原文:golang protobuf序列化分析

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1045 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传