github.com/ergo-services/ergo@v1.999.224/etf/etf.go (about) 1 package etf 2 3 import ( 4 "fmt" 5 "hash/crc32" 6 "reflect" 7 "strings" 8 "sync" 9 10 "github.com/ergo-services/ergo/lib" 11 ) 12 13 var ( 14 registered = registeredTypes{ 15 typesEnc: make(map[Atom]*registerType), 16 typesDec: make(map[Atom]*registerType), 17 } 18 ) 19 20 // Erlang external term tags. 21 const ( 22 ettAtom = byte(100) //deprecated 23 ettAtomUTF8 = byte(118) 24 ettSmallAtom = byte(115) //deprecated 25 ettSmallAtomUTF8 = byte(119) 26 ettString = byte(107) 27 28 ettCacheRef = byte(82) 29 30 ettNewFloat = byte(70) 31 32 ettSmallInteger = byte(97) 33 ettInteger = byte(98) 34 ettLargeBig = byte(111) 35 ettSmallBig = byte(110) 36 37 ettList = byte(108) 38 ettListImproper = byte(18) // to be able to encode improper lists like [a|b]. 39 ettSmallTuple = byte(104) 40 ettLargeTuple = byte(105) 41 42 ettMap = byte(116) 43 44 ettBinary = byte(109) 45 ettBitBinary = byte(77) 46 47 ettNil = byte(106) 48 49 ettPid = byte(103) 50 ettNewPid = byte(88) // since OTP 23, only when BIG_CREATION flag is set 51 ettNewRef = byte(114) 52 ettNewerRef = byte(90) // since OTP 21, only when BIG_CREATION flag is set 53 54 ettExport = byte(113) 55 ettFun = byte(117) // legacy, wont support it here 56 ettNewFun = byte(112) 57 58 ettPort = byte(102) 59 ettNewPort = byte(89) // since OTP 23, only when BIG_CREATION flag is set 60 61 // ettRef = byte(101) deprecated 62 63 ettFloat = byte(99) // legacy 64 ) 65 66 type registeredTypes struct { 67 sync.RWMutex 68 typesEnc map[Atom]*registerType 69 typesDec map[Atom]*registerType 70 } 71 type registerType struct { 72 rtype reflect.Type 73 name Atom 74 origin Atom 75 strict bool 76 } 77 78 // Term 79 type Term interface{} 80 81 // Tuple 82 type Tuple []Term 83 84 // List 85 type List []Term 86 87 // Alias 88 type Alias Ref 89 90 // ListImproper as a workaround for the Erlang's improper list [a|b]. Intended to be used to interact with Erlang. 91 type ListImproper []Term 92 93 // Atom 94 type Atom string 95 96 // Map 97 type Map map[Term]Term 98 99 // String this type is intended to be used to interact with Erlang. String value encodes as a binary (Erlang type: <<...>>) 100 type String string 101 102 // Charlist this type is intended to be used to interact with Erlang. Charlist value encodes as a list of int32 numbers in order to support Erlang string with UTF-8 symbols on an Erlang side (Erlang type: [...]) 103 type Charlist string 104 105 // Pid 106 type Pid struct { 107 Node Atom 108 ID uint64 109 Creation uint32 110 } 111 112 // Port 113 type Port struct { 114 Node Atom 115 ID uint32 116 Creation uint32 117 } 118 119 // Ref 120 type Ref struct { 121 Node Atom 122 Creation uint32 123 ID [5]uint32 124 } 125 126 // Marshaler interface implemented by types that can marshal themselves into valid ETF binary 127 // Interface implementation must be over the object e.g. (MyObject) UnmarshalETF: 128 // 129 // type MyObject struct{} 130 // 131 // func (m MyObject) MarshalETF() ([]byte, error) { 132 // var encoded []byte 133 // ... encoding routine ... 134 // return encoded, nil 135 // } 136 type Marshaler interface { 137 MarshalETF() ([]byte, error) 138 } 139 140 // Unmarshaler interface implemented by types that can unmarshal an ETF binary of themselves. 141 // Returns error ErrEmpty for []byte{}. 142 // Interface implementation must be over pointer to the object e.g. (*MyObject) UnmarshalETF: 143 // 144 // type MyObject struct{} 145 // 146 // func (m *MyObject) UnmarshalETF(b []byte) error { 147 // var err error 148 // ... decoding routine ... 149 // return err 150 // } 151 type Unmarshaler interface { 152 UnmarshalETF([]byte) error 153 } 154 155 // Function 156 type Function struct { 157 Arity byte 158 Unique [16]byte 159 Index uint32 160 // Free uint32 161 Module Atom 162 OldIndex uint32 163 OldUnique uint32 164 Pid Pid 165 FreeVars []Term 166 } 167 168 // Export 169 type Export struct { 170 Module Atom 171 Function Atom 172 Arity int 173 } 174 175 // Element 176 func (m Map) Element(k Term) Term { 177 return m[k] 178 } 179 180 // Element 181 func (l List) Element(i int) Term { 182 return l[i-1] 183 } 184 185 // Element 186 func (t Tuple) Element(i int) Term { 187 return t[i-1] 188 } 189 190 // String 191 func (p Pid) String() string { 192 empty := Pid{} 193 if p == empty { 194 return "<0.0.0>" 195 } 196 197 n := uint32(0) 198 if p.Node != "" { 199 n = crc32.Checksum([]byte(p.Node), lib.CRC32Q) 200 } 201 return fmt.Sprintf("<%08X.%d.%d>", n, int32(p.ID>>32), int32(p.ID)) 202 } 203 204 // String 205 func (r Ref) String() string { 206 n := uint32(0) 207 if r.Node != "" { 208 n = crc32.Checksum([]byte(r.Node), lib.CRC32Q) 209 } 210 return fmt.Sprintf("Ref#<%08X.%d.%d.%d>", n, r.ID[0], r.ID[1], r.ID[2]) 211 } 212 213 // String 214 func (a Alias) String() string { 215 n := uint32(0) 216 if a.Node != "" { 217 n = crc32.Checksum([]byte(a.Node), lib.CRC32Q) 218 } 219 return fmt.Sprintf("Ref#<%08X.%d.%d.%d>", n, a.ID[0], a.ID[1], a.ID[2]) 220 } 221 222 // ProplistElement 223 type ProplistElement struct { 224 Name Atom 225 Value Term 226 } 227 228 // TermToString transforms given term (Atom, []byte, List) to the string 229 func TermToString(t Term) (s string, ok bool) { 230 ok = true 231 switch x := t.(type) { 232 case Atom: 233 s = string(x) 234 case string: 235 s = x 236 case []byte: 237 s = string(x) 238 case List: 239 str, err := convertCharlistToString(x) 240 if err != nil { 241 ok = false 242 return 243 } 244 s = str 245 default: 246 ok = false 247 } 248 return 249 } 250 251 // TermProplistIntoStruct transorms given term into the provided struct 'dest'. 252 // Proplist is the list of Tuple values with two items { Name , Value }, 253 // where Name can be string or Atom and Value must be the same type as 254 // it has the field of 'dest' struct with the equivalent name. Its also 255 // accepts []ProplistElement as a 'term' value 256 func TermProplistIntoStruct(term Term, dest interface{}) (err error) { 257 defer func() { 258 if r := recover(); r != nil { 259 err = fmt.Errorf("%v", r) 260 } 261 }() 262 v := reflect.Indirect(reflect.ValueOf(dest)) 263 return setProplist(term, v) 264 } 265 266 // TermIntoStruct transforms 'term' (etf.Term, etf.List, etf.Tuple, etf.Map) into the 267 // given 'dest' (could be a struct, map, slice or array). Its a pretty 268 // expencive operation in terms of CPU usage so you shouldn't use it 269 // on highload parts of your code. Use manual type casting instead. 270 func TermIntoStruct(term Term, dest interface{}) (err error) { 271 defer func() { 272 if r := recover(); r != nil { 273 err = fmt.Errorf("%v", r) 274 } 275 }() 276 v := reflect.Indirect(reflect.ValueOf(dest)) 277 err = termIntoStruct(term, v) 278 return 279 } 280 281 func termIntoStruct(term Term, dest reflect.Value) error { 282 283 if term == nil { 284 return nil 285 } 286 287 if dest.Type().NumMethod() > 0 && dest.CanInterface() { 288 v := dest 289 if v.Kind() != reflect.Ptr && v.CanAddr() { 290 v = v.Addr() 291 292 if u, ok := v.Interface().(Unmarshaler); ok { 293 b, is_binary := term.([]byte) 294 if !is_binary { 295 return fmt.Errorf("can't unmarshal value, wront type %s", term) 296 } 297 return u.UnmarshalETF(b) 298 } 299 } 300 } 301 302 switch dest.Kind() { 303 case reflect.Ptr: 304 pdest := reflect.New(dest.Type().Elem()) 305 dest.Set(pdest) 306 dest = pdest.Elem() 307 return termIntoStruct(term, dest) 308 309 case reflect.Array, reflect.Slice: 310 t := dest.Type() 311 byte_slice, ok := term.([]byte) 312 if t == reflect.SliceOf(reflect.TypeOf(byte(1))) && ok { 313 dest.Set(reflect.ValueOf(byte_slice)) 314 return nil 315 316 } 317 if _, ok := term.(List); !ok { 318 // in case if term is the golang native type 319 dest.Set(reflect.ValueOf(term)) 320 return nil 321 } 322 return setListField(term.(List), dest) 323 324 case reflect.Struct: 325 switch s := term.(type) { 326 case Map: 327 return setMapStructField(s, dest) 328 case Tuple: 329 return setStructField(s, dest) 330 case Ref: 331 dest.Set(reflect.ValueOf(s)) 332 return nil 333 case Pid: 334 dest.Set(reflect.ValueOf(s)) 335 return nil 336 } 337 return fmt.Errorf("can't convert %#v to struct", term) 338 339 case reflect.Map: 340 if _, ok := term.(Map); !ok { 341 // in case if term is the golang native type 342 dest.Set(reflect.ValueOf(term)) 343 return nil 344 } 345 return setMapField(term.(Map), dest) 346 347 case reflect.Bool: 348 b, ok := term.(bool) 349 if !ok { 350 return fmt.Errorf("can't convert %#v to bool", term) 351 } 352 dest.SetBool(b) 353 return nil 354 355 case reflect.Float32, reflect.Float64: 356 f, ok := term.(float64) 357 if !ok { 358 return fmt.Errorf("can't convert %#v to float64", term) 359 } 360 dest.SetFloat(f) 361 return nil 362 363 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 364 i := int64(0) 365 switch v := term.(type) { 366 case int64: 367 i = v 368 case int32: 369 i = int64(v) 370 case int16: 371 i = int64(v) 372 case int8: 373 i = int64(v) 374 case int: 375 i = int64(v) 376 case uint64: 377 i = int64(v) 378 case uint32: 379 i = int64(v) 380 case uint16: 381 i = int64(v) 382 case uint8: 383 i = int64(v) 384 case uint: 385 i = int64(v) 386 default: 387 return fmt.Errorf("can't convert %#v to int64", term) 388 } 389 dest.SetInt(i) 390 return nil 391 392 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 393 u := uint64(0) 394 switch v := term.(type) { 395 case uint64: 396 u = v 397 case uint32: 398 u = uint64(v) 399 case uint16: 400 u = uint64(v) 401 case uint8: 402 u = uint64(v) 403 case uint: 404 u = uint64(v) 405 case int64: 406 u = uint64(v) 407 case int32: 408 u = uint64(v) 409 case int16: 410 u = uint64(v) 411 case int8: 412 u = uint64(v) 413 case int: 414 u = uint64(v) 415 416 default: 417 return fmt.Errorf("can't convert %#v to uint64", term) 418 } 419 dest.SetUint(u) 420 return nil 421 422 case reflect.String: 423 switch v := term.(type) { 424 case List: 425 s, err := convertCharlistToString(v) 426 if err != nil { 427 return err 428 } 429 dest.SetString(s) 430 return nil 431 case []byte: 432 dest.SetString(string(v)) 433 return nil 434 case string: 435 dest.SetString(v) 436 return nil 437 case Atom: 438 dest.SetString(string(v)) 439 return nil 440 } 441 442 default: 443 dest.Set(reflect.ValueOf(term)) 444 return nil 445 } 446 447 return nil 448 } 449 450 func setListField(term List, dest reflect.Value) error { 451 var value reflect.Value 452 if dest.Kind() == reflect.Ptr { 453 pdest := reflect.New(dest.Type().Elem()) 454 dest.Set(pdest) 455 dest = pdest.Elem() 456 } 457 t := dest.Type() 458 switch t.Kind() { 459 case reflect.Slice: 460 value = reflect.MakeSlice(t, len(term), len(term)) 461 case reflect.Array: 462 if t.Len() != len(term) { 463 return NewInvalidTypesError(t, term) 464 } 465 value = dest 466 default: 467 return NewInvalidTypesError(t, term) 468 } 469 470 for i, elem := range term { 471 if err := termIntoStruct(elem, value.Index(i)); err != nil { 472 return err 473 } 474 } 475 476 if t.Kind() == reflect.Slice { 477 dest.Set(value) 478 } 479 480 return nil 481 } 482 483 func setProplist(term Term, dest reflect.Value) error { 484 switch v := term.(type) { 485 case []ProplistElement: 486 return setProplistElementField(v, dest) 487 case List: 488 return setProplistField(v, dest) 489 default: 490 return NewInvalidTypesError(dest.Type(), term) 491 } 492 493 } 494 495 func setProplistField(list List, dest reflect.Value) error { 496 t := dest.Type() 497 numField := t.NumField() 498 fields := make([]reflect.StructField, numField) 499 for i := range fields { 500 fields[i] = t.Field(i) 501 } 502 503 for _, elem := range list { 504 if len(elem.(Tuple)) != 2 { 505 return &InvalidStructKeyError{Term: elem} 506 } 507 508 key := elem.(Tuple)[0] 509 val := elem.(Tuple)[1] 510 fName, ok := TermToString(key) 511 if !ok { 512 return &InvalidStructKeyError{Term: key} 513 } 514 index := findStructField(fields, fName) 515 if index == -1 { 516 continue 517 } 518 519 err := termIntoStruct(val, dest.Field(index)) 520 if err != nil { 521 return err 522 } 523 } 524 525 return nil 526 } 527 528 func setProplistElementField(proplist []ProplistElement, dest reflect.Value) error { 529 t := dest.Type() 530 numField := t.NumField() 531 fields := make([]reflect.StructField, numField) 532 for i := range fields { 533 fields[i] = t.Field(i) 534 } 535 536 for _, elem := range proplist { 537 fName, ok := TermToString(elem.Name) 538 if !ok { 539 return &InvalidStructKeyError{Term: elem.Name} 540 } 541 index := findStructField(fields, fName) 542 if index == -1 { 543 continue 544 } 545 546 err := termIntoStruct(elem.Value, dest.Field(index)) 547 if err != nil { 548 return err 549 } 550 } 551 552 return nil 553 } 554 func setMapField(term Map, dest reflect.Value) error { 555 switch dest.Type().Kind() { 556 case reflect.Map: 557 return setMapMapField(term, dest) 558 case reflect.Struct: 559 return setMapStructField(term, dest) 560 case reflect.Interface: 561 dest.Set(reflect.ValueOf(term)) 562 return nil 563 } 564 565 return NewInvalidTypesError(dest.Type(), term) 566 } 567 568 func setStructField(term Tuple, dest reflect.Value) error { 569 if dest.Kind() == reflect.Ptr { 570 pdest := reflect.New(dest.Type().Elem()) 571 dest.Set(pdest) 572 dest = pdest.Elem() 573 } 574 for i, elem := range term { 575 // let it panic if number of term elements is bigger than 576 // number of struct fields 577 if err := termIntoStruct(elem, dest.Field(i)); err != nil { 578 return err 579 } 580 } 581 582 return nil 583 584 } 585 586 func setMapStructField(term Map, dest reflect.Value) error { 587 t := dest.Type() 588 numField := t.NumField() 589 fields := make([]reflect.StructField, numField) 590 for i := range fields { 591 fields[i] = t.Field(i) 592 } 593 594 for key, val := range term { 595 fName, ok := TermToString(key) 596 if !ok { 597 return &InvalidStructKeyError{Term: key} 598 } 599 index := findStructField(fields, fName) 600 if index == -1 { 601 continue 602 } 603 604 err := termIntoStruct(val, dest.Field(index)) 605 if err != nil { 606 return err 607 } 608 } 609 610 return nil 611 } 612 613 func findStructField(term []reflect.StructField, key string) (index int) { 614 var fieldName string 615 index = -1 616 for i, f := range term { 617 fieldName = f.Name 618 619 if tag := f.Tag.Get("etf"); tag != "" { 620 fieldName = tag 621 } 622 623 if fieldName == key { 624 index = i 625 return 626 } else { 627 if strings.EqualFold(f.Name, key) { 628 index = i 629 } 630 } 631 } 632 633 return 634 } 635 636 func setMapMapField(term Map, dest reflect.Value) error { 637 t := dest.Type() 638 if dest.IsNil() { 639 dest.Set(reflect.MakeMapWithSize(t, len(term))) 640 } 641 tkey := t.Key() 642 tval := t.Elem() 643 for key, val := range term { 644 destkey := reflect.Indirect(reflect.New(tkey)) 645 if err := termIntoStruct(key, destkey); err != nil { 646 return err 647 } 648 destval := reflect.Indirect(reflect.New(tval)) 649 if err := termIntoStruct(val, destval); err != nil { 650 return err 651 } 652 dest.SetMapIndex(destkey, destval) 653 } 654 return nil 655 } 656 657 // RegisterTypeOptins defines custom name for the registering type. 658 // Leaving the Name option empty makes the name automatically generated. 659 // Strict option defines whether the decoding process causes panic 660 // if the decoding value doesn't fit the destination object. 661 type RegisterTypeOptions struct { 662 Name Atom 663 Strict bool 664 } 665 666 // RegisterType registers new type with the given options. It returns a Name 667 // of the registered type, which can be used in the UnregisterType function 668 // for unregistering this type. Supported types: struct, slice, array, map. 669 // Returns an error if this type can not be registered. 670 func RegisterType(t interface{}, options RegisterTypeOptions) (Atom, error) { 671 switch t.(type) { 672 case Pid, Ref, Alias: 673 return "", fmt.Errorf("types Pid, Ref, Alias can not be registered") 674 } 675 tt := reflect.TypeOf(t) 676 ttk := tt.Kind() 677 678 name := options.Name 679 origin := regTypeName(tt) 680 if name == "" { 681 name = origin 682 } 683 lname := len([]rune(name)) 684 if lname > 255 { 685 return name, fmt.Errorf("type name %q is too long. characters number %d (limit: 255)", name, lname) 686 } 687 688 switch ttk { 689 case reflect.Struct, reflect.Slice, reflect.Array: 690 case reflect.Map: 691 // Using pointers for the network messaging is meaningless. 692 // Supporting this feature in the maps is getting the decoding process a bit overloaded. 693 // But they still can be used for the other types, even being meaningless. 694 if tt.Key().Kind() == reflect.Ptr { 695 return name, fmt.Errorf("pointer as a key for the map is not supported") 696 } 697 if tt.Elem().Kind() == reflect.Ptr { 698 return name, fmt.Errorf("pointer as a value for the map is not supported") 699 } 700 // supported types 701 default: 702 return name, fmt.Errorf("type %q is not supported", regTypeName(tt)) 703 } 704 705 registered.Lock() 706 defer registered.Unlock() 707 708 _, taken := registered.typesDec[name] 709 if taken { 710 return name, lib.ErrTaken 711 } 712 713 r, taken := registered.typesEnc[origin] 714 if taken { 715 return name, fmt.Errorf("type is already registered as %q", r.name) 716 } 717 718 checkIsRegistered := func(name Atom, rt reflect.Kind) error { 719 switch rt { 720 case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map: 721 // check if this type is registered 722 _, taken := registered.typesEnc[name] 723 if taken == false { 724 return fmt.Errorf("type %q must be registered first", name) 725 } 726 case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Complex64, reflect.Complex128: 727 return fmt.Errorf("type %q is not supported", rt) 728 } 729 return nil 730 } 731 732 switch ttk { 733 case reflect.Struct: 734 // check for unexported fields 735 tv := reflect.ValueOf(t) 736 for i := 0; i < tv.NumField(); i++ { 737 f := tv.Field(i) 738 if f.CanInterface() == false { 739 return name, fmt.Errorf("struct has unexported field(s)") 740 } 741 742 switch f.Interface().(type) { 743 case Pid, Ref, Alias: 744 // ignore this types 745 continue 746 } 747 748 if f.Type().Kind() == reflect.Slice && f.Type().Elem().Kind() == reflect.Uint8 { 749 // []byte 750 continue 751 } 752 753 orig := regTypeName(f.Type()) 754 if err := checkIsRegistered(orig, f.Kind()); err != nil { 755 return name, err 756 } 757 } 758 case reflect.Array, reflect.Slice, reflect.Map: 759 elem := tt.Elem() 760 orig := regTypeName(elem) 761 if err := checkIsRegistered(orig, elem.Kind()); err != nil { 762 return name, err 763 } 764 } 765 766 rt := ®isterType{ 767 rtype: reflect.TypeOf(t), 768 name: name, 769 origin: origin, 770 strict: options.Strict, 771 } 772 registered.typesEnc[origin] = rt 773 registered.typesDec[name] = rt 774 return name, nil 775 } 776 777 // UnregisterType unregisters type with a given name. 778 func UnregisterType(name Atom) error { 779 registered.Lock() 780 defer registered.Unlock() 781 r, found := registered.typesDec[name] 782 if found == false { 783 return lib.ErrUnknown 784 } 785 delete(registered.typesDec, name) 786 delete(registered.typesEnc, r.origin) 787 return nil 788 } 789 790 type StructPopulatorError struct { 791 Type reflect.Type 792 Term Term 793 } 794 795 func (s *StructPopulatorError) Error() string { 796 return fmt.Sprintf("Cannot put %#v into go value of type %s", s.Term, s.Type.Kind().String()) 797 } 798 799 func NewInvalidTypesError(t reflect.Type, term Term) error { 800 return &StructPopulatorError{ 801 Type: t, 802 Term: term, 803 } 804 } 805 806 type InvalidStructKeyError struct { 807 Term Term 808 } 809 810 func (s *InvalidStructKeyError) Error() string { 811 return fmt.Sprintf("Cannot use %s as struct field name", reflect.TypeOf(s.Term).Name()) 812 } 813 814 func convertCharlistToString(l List) (string, error) { 815 runes := make([]rune, len(l)) 816 for i := range l { 817 switch x := l[i].(type) { 818 case int64: 819 runes[i] = int32(x) 820 case int32: 821 runes[i] = int32(x) 822 case int16: 823 runes[i] = int32(x) 824 case int8: 825 runes[i] = int32(x) 826 case int: 827 runes[i] = int32(x) 828 default: 829 return "", fmt.Errorf("wrong rune %#v", l[i]) 830 } 831 } 832 return string(runes), nil 833 } 834 835 func regTypeName(t reflect.Type) Atom { 836 return Atom("#" + t.PkgPath() + "/" + t.Name()) 837 }