github.com/RomiChan/protobuf@v0.1.1-0.20230204044148-2ed269a2e54d/proto/struct.go (about)

     1  package proto
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strconv"
     7  	"strings"
     8  	"unsafe"
     9  )
    10  
    11  type structInfo struct {
    12  	fields     []*structField
    13  	fieldIndex map[fieldNumber]*structField
    14  }
    15  
    16  type structField struct {
    17  	offset  uintptr
    18  	wiretag uint64
    19  	codec   *codec
    20  	tagsize int
    21  }
    22  
    23  func (f *structField) fieldNumber() fieldNumber {
    24  	return fieldNumber(f.wiretag >> 3)
    25  }
    26  
    27  func (f *structField) wireType() wireType {
    28  	return wireType(f.wiretag & 7)
    29  }
    30  
    31  func (f *structField) pointer(p unsafe.Pointer) unsafe.Pointer {
    32  	return unsafe.Pointer(uintptr(p) + f.offset)
    33  }
    34  
    35  func (info *structInfo) size(p unsafe.Pointer) int {
    36  	if p == nil {
    37  		return 0
    38  	}
    39  	n := 0
    40  	for _, f := range info.fields {
    41  		n += f.codec.size(f.pointer(p), f)
    42  	}
    43  	return n
    44  }
    45  
    46  func (info *structInfo) encode(b []byte, p unsafe.Pointer) []byte {
    47  	if p == nil {
    48  		return b
    49  	}
    50  	for _, f := range info.fields {
    51  		b = f.codec.encode(b, f.pointer(p), f)
    52  	}
    53  	return b
    54  }
    55  
    56  func (info *structInfo) decode(b []byte, p unsafe.Pointer) (int, error) {
    57  	offset := 0
    58  	for offset < len(b) {
    59  		fieldNumber, wireType, n, err := decodeTag(b[offset:])
    60  		offset += n
    61  		if err != nil {
    62  			return offset, err
    63  		}
    64  
    65  		f := info.fieldIndex[fieldNumber]
    66  		if f == nil {
    67  			skip := 0
    68  			size := uint64(0)
    69  			switch wireType {
    70  			case varint:
    71  				_, skip, err = decodeVarint(b[offset:])
    72  			case varlen:
    73  				size, skip, err = decodeVarint(b[offset:])
    74  				if err == nil {
    75  					if size > uint64(len(b)-skip) {
    76  						err = io.ErrUnexpectedEOF
    77  					} else {
    78  						skip += int(size)
    79  					}
    80  				}
    81  			case fixed32:
    82  				skip = 4
    83  			case fixed64:
    84  				skip = 8
    85  			default:
    86  				err = ErrWireTypeUnknown
    87  			}
    88  			if (offset + skip) <= len(b) {
    89  				offset += skip
    90  			} else {
    91  				offset, err = len(b), io.ErrUnexpectedEOF
    92  			}
    93  			if err != nil {
    94  				return offset, fieldError(fieldNumber, wireType, err)
    95  			}
    96  			continue
    97  		}
    98  
    99  		if wireType != f.wireType() {
   100  			return offset, fieldError(fieldNumber, wireType, fmt.Errorf("expected wire type %d", f.wireType()))
   101  		}
   102  
   103  		// `data` will only contain the section of the input buffer where
   104  		// the data for the next field is available. This is necessary to
   105  		// limit how many bytes will be consumed by embedded messages.
   106  		var data []byte
   107  		switch wireType {
   108  		case varint:
   109  			_, n, err := decodeVarint(b[offset:])
   110  			if err != nil {
   111  				return offset, fieldError(fieldNumber, wireType, err)
   112  			}
   113  			data = b[offset : offset+n]
   114  
   115  		case varlen:
   116  			l, n, err := decodeVarint(b[offset:])
   117  			if err != nil {
   118  				return offset + n, fieldError(fieldNumber, wireType, err)
   119  			}
   120  			if l > uint64(len(b)-(offset+n)) {
   121  				return len(b), fieldError(fieldNumber, wireType, io.ErrUnexpectedEOF)
   122  			}
   123  			data = b[offset : offset+n+int(l)]
   124  
   125  		case fixed32:
   126  			if (offset + 4) > len(b) {
   127  				return len(b), fieldError(fieldNumber, wireType, io.ErrUnexpectedEOF)
   128  			}
   129  			data = b[offset : offset+4]
   130  
   131  		case fixed64:
   132  			if (offset + 8) > len(b) {
   133  				return len(b), fieldError(fieldNumber, wireType, io.ErrUnexpectedEOF)
   134  			}
   135  			data = b[offset : offset+8]
   136  
   137  		default:
   138  			return offset, fieldError(fieldNumber, wireType, ErrWireTypeUnknown)
   139  		}
   140  
   141  		n, err = f.codec.decode(data, f.pointer(p))
   142  		offset += n
   143  		if err != nil {
   144  			return offset, fieldError(fieldNumber, wireType, err)
   145  		}
   146  	}
   147  
   148  	return offset, nil
   149  }
   150  
   151  type structTag struct {
   152  	// version     int
   153  	wireType    wireType
   154  	fieldNumber fieldNumber
   155  	repeated    bool
   156  	zigzag      bool
   157  }
   158  
   159  func parseStructTag(tag string) (structTag, error) {
   160  	t := structTag{
   161  		// version:    2,
   162  	}
   163  
   164  	for i, f := range splitFields(tag) {
   165  		switch i {
   166  		case 0:
   167  			switch f {
   168  			case "varint":
   169  				t.wireType = varint
   170  			case "bytes":
   171  				t.wireType = varlen
   172  			case "fixed32":
   173  				t.wireType = fixed32
   174  			case "fixed64":
   175  				t.wireType = fixed64
   176  			case "zigzag32":
   177  				t.wireType = varint
   178  				t.zigzag = true
   179  			case "zigzag64":
   180  				t.wireType = varint
   181  				t.zigzag = true
   182  			default:
   183  				return t, fmt.Errorf("unsupported wire type in struct tag %q: %s", tag, f)
   184  			}
   185  
   186  		case 1:
   187  			n, err := strconv.Atoi(f)
   188  			if err != nil {
   189  				return t, fmt.Errorf("unsupported field number in struct tag %q: %w", tag, err)
   190  			}
   191  			t.fieldNumber = fieldNumber(n)
   192  
   193  		case 2:
   194  			switch f {
   195  			case "opt":
   196  				// not sure what this is for
   197  			case "rep":
   198  				t.repeated = true
   199  			default:
   200  				return t, fmt.Errorf("unsupported field option in struct tag %q: %s", tag, f)
   201  			}
   202  
   203  		default:
   204  			/*
   205  				name, value := splitNameValue(f)
   206  				switch name {
   207  				case "name":
   208  					t.name = value
   209  				case "enum":
   210  					t.enum = value
   211  				case "json":
   212  					t.json = value
   213  				case "proto3":
   214  					t.version = 3
   215  				default:
   216  					t.extensions[name] = value
   217  				}
   218  			*/
   219  		}
   220  	}
   221  
   222  	return t, nil
   223  }
   224  
   225  func splitFields(s string) []string {
   226  	return strings.Split(s, ",")
   227  }
   228  
   229  /*
   230  func splitNameValue(s string) (name, value string) {
   231  	i := strings.IndexByte(s, '=')
   232  	if i < 0 {
   233  		return strings.TrimSpace(s), ""
   234  	} else {
   235  		return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+1:])
   236  	}
   237  }
   238  */