1 // pubsubplus-go-client 2 // 3 // Copyright 2021-2024 Solace Corporation. All rights reserved. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 // Package sdt contains the types needed to work with Structured Data on a message. 18 // In particular, two main data types are provided, sdt.Map and sdt.Stream. They can both be 19 // used as normal Golang maps and slices as well as can be passed as a payload on a message. 20 // When retrieved, a map will contain the converted data converted as per the table on sdt.Data. 21 // Furthermore, data types can be converted using the various getters such as GetBool which will 22 // attempt to convert the specified data into a builtin.bool. 23 package sdt 24 25 import ( 26 "fmt" 27 "strconv" 28 "unsafe" 29 30 "solace.dev/go/messaging/pkg/solace/resource" 31 ) 32 33 // Map represents a map between strings and values that can be converted into structured 34 // data types in a message payload. Accepts any valid sdt.Data types. 35 type Map map[string]Data 36 37 // Stream represents a stream of data that can be converted into structured data types 38 // in a message payload. Accepts any valid sdt.Data types. 39 type Stream []Data 40 41 // Data represents valid types that can be used in sdt.Map and sdt.Stream instances. 42 // Valid types are: int, uint, nil, bool, uint8, uint16, uint32, uint64, int8, int16, int32, 43 // int64, string, rune, float32, float64, byte, []byte, sdt.WChar, resource.Destination, 44 // sdt.Map and sdt.Stream. 45 // 46 // Message type mapping is as follows: 47 // solClient_fieldType Golang Type 48 // SOLCLIENT_BOOL bool 49 // SOLCLIENT_UINT8 uint8 50 // SOLCLIENT_INT8 int8 51 // SOLCLIENT_UINT16 uint16 52 // SOLCLIENT_INT16 int16 53 // SOLCLIENT_UINT32 uint32 54 // SOLCLIENT_INT32 int32 55 // SOLCLIENT_UINT64 uint64 56 // SOLCLIENT_INT64 int64 57 // SOLCLIENT_WCHAR sdt.WChar 58 // SOLCLIENT_STRING string 59 // SOLCLIENT_BYTEARRAY []byte 60 // SOLCLIENT_FLOAT float32 61 // SOLCLIENT_DOUBLE float64 62 // SOLCLIENT_MAP sdt.Map 63 // SOLCLIENT_STREAM sdt.Stream 64 // SOLCLIENT_NULL nil 65 // SOLCLIENT_DESTINATION solace.Destination (solace.Queue or solace.Topic) 66 // SOLCLIENT_UNKNOWN []byte 67 // 68 // On outbound messages, the following additional types are supported with the following mappings: 69 // 70 // byte SOLCLIENT_INT8 71 // int SOLCLIENT_INT64 72 // uint SOLCLIENT_UINT64 73 // rune SOLCLIENT_INT32 74 // 75 // Notes on mappings: 76 // 77 // - int is always be converted to int64, even when on 32-bit architectures 78 // 79 // - uint is always be converted to uint64, even when on 32-bit architectures 80 // 81 // - byte is the same as int8 and is mapped accordingly 82 // 83 // In addition to these mappings, client-side conversions may be made to retrieve data 84 // in the type you want. The following table is used to determine these conversions: 85 // 86 // Type | bool | byte | int | uint | uint8 | int8 | uint16 | int16 | uint32 | int32 | uint64 | int64 | []byte | float32 | float64 | string | WChar | 87 // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 88 // bool | x x x x x x x x x x x x x 89 // byte | x x x x x x x x x x x x x 90 // int | x x x x x x x x x x x x x 91 // uint | x x x x x x x x x x x x x 92 // uint8 | x x x x x x x x x x x x x 93 // int8 | x x x x x x x x x x x x x 94 // uint16 | x x x x x x x x x x x x x 95 // int16 | x x x x x x x x x x x x x 96 // uint32 | x x x x x x x x x x x x x 97 // int32 | x x x x x x x x x x x x x 98 // uint64 | x x x x x x x x x x x x x 99 // int64 | x x x x x x x x x x x x x 100 // []byte | x x 101 // float32 | x x 102 // float64 | x x 103 // string | x x 104 // WChar | x x x x 105 // 106 // For each integer-type conversion, the value will be converted if it is 107 // within the range of the requested type, otherwise a conversion error 108 // will be thrown indicating that the value is outside the domain. 109 // String types will be converted to integers using strconv.Stoi and 110 // then returned if it is within the range of the requested type. 111 // For boolean conversions from integer types, all non-zero values map to true. 112 // For boolean conversion from strings, "true" and "1" map to true, "false" and 113 // "0" map to false, and all other strings are not converted. WChar conversion 114 // converts strings of length 1 into a WChar. All other strings are rejected. 115 // 116 // In addition, the following one-to-one conversions are used: 117 // 118 // sdt.Map, sdt.Stream 119 // 120 // Lastly, Destination is mapped with these getters: 121 // 122 // GetQueue, GetTopic, and GetDestination 123 type Data interface{} 124 125 // WChar represents the wide character type. WChar is a uint16 value 126 // holding UTF-16 data. On publish, this value is converted into 127 // SOLCLIENT_WCHAR, and on receive SOLCLIENT_WCHAR is converted into 128 // WChar. 129 type WChar uint16 130 131 // KeyNotFoundError is returned if the requested key is not found. 132 type KeyNotFoundError struct { 133 // Key is the key that was being accessed and does not exist. 134 Key string 135 } 136 137 func (err *KeyNotFoundError) Error() string { 138 return fmt.Sprintf("could not find mapping for key %s", err.Key) 139 } 140 141 // OutOfBoundsError is returned if the specified index is out of bounds. 142 type OutOfBoundsError struct { 143 Index int 144 } 145 146 func (err *OutOfBoundsError) Error() string { 147 return fmt.Sprintf("index %d is out of bounds", err.Index) 148 } 149 150 // FormatConversionError is returned if there is an error converting 151 // stored data to a specified return type. 152 type FormatConversionError struct { 153 // Message is the message of the error 154 Message string 155 // Data is the data that could not be converted. 156 Data interface{} 157 } 158 159 // Error implements the error interface and returns the error message as string. 160 func (err *FormatConversionError) Error() string { 161 return err.Message 162 } 163 164 func defaultFormatConversionError(data interface{}, desiredType string) *FormatConversionError { 165 return &FormatConversionError{ 166 Message: fmt.Sprintf("cannot convert %T to %s", data, desiredType), 167 Data: data, 168 } 169 } 170 171 func nestedFormatConversionError(data interface{}, desiredType string, nested error) *FormatConversionError { 172 return &FormatConversionError{ 173 Message: fmt.Sprintf("cannot convert %T to %s: %s", data, desiredType, nested.Error()), 174 Data: data, 175 } 176 } 177 178 // IllegalTypeError is returned if an error occurs while encoding a stored 179 // type to a message when setting a payload or user property. 180 type IllegalTypeError struct { 181 Data interface{} 182 } 183 184 // Error implements the error interface and returns the error message as string. 185 func (err *IllegalTypeError) Error() string { 186 return fmt.Sprintf("type %T is not a valid instance of sdt.Data", err.Data) 187 } 188 189 // GetBool retrieves the data using the specified key and attempts to convert the 190 // data into a boolean form, if necessary. Returns the boolean value of the 191 // field, and one of the following errors if it occurred: 192 // 193 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 194 // 195 // - sdt.FormatConversionError - If the data cannot be converted into boolean form. 196 func (sdtMap Map) GetBool(key string) (val bool, err error) { 197 elem, ok := sdtMap[key] 198 if !ok { 199 return false, &KeyNotFoundError{key} 200 } 201 return getBool(elem) 202 } 203 204 // GetByte retrieves the data at the specified key and attempt to convert the 205 // data into byte form if necessary. Returns the byte value of the field, 206 // and one of the following errors if it occurred: 207 // 208 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 209 // 210 // - sdt.FormatConversionError - If the data cannot be converted into byte form. 211 func (sdtMap Map) GetByte(key string) (val byte, err error) { 212 elem, ok := sdtMap[key] 213 if !ok { 214 return 0, &KeyNotFoundError{key} 215 } 216 return getUint8(elem) 217 } 218 219 // GetInt retrieves the data at the specified key and attempt to convert the 220 // data into int form if necessary. Returns the int value of the 221 // field, and one of the following errors if it occurred: 222 // 223 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 224 // 225 // - sdt.FormatConversionError - If the data cannot be converted into int form. 226 func (sdtMap Map) GetInt(key string) (val int, err error) { 227 elem, ok := sdtMap[key] 228 if !ok { 229 return 0, &KeyNotFoundError{key} 230 } 231 return getInt(elem) 232 } 233 234 // GetUInt retrieves the data at the specified key and attempt to convert the 235 // data into uint form if necessary. Returns the uint value of the 236 // field, and one of the following errors if it occurred: 237 // 238 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 239 // 240 // - sdt.FormatConversionError - If the data cannot be converted into uint form. 241 func (sdtMap Map) GetUInt(key string) (val uint, err error) { 242 elem, ok := sdtMap[key] 243 if !ok { 244 return 0, &KeyNotFoundError{key} 245 } 246 return getUint(elem) 247 } 248 249 // GetInt8 retrieves the data at the specified key and attempt to convert the 250 // data into int8 form if necessary. Returns the int8 value of the 251 // field, and one of the following errors if it occurred: 252 // 253 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 254 // 255 // - sdt.FormatConversionError - If the data cannot be converted into int8 form. 256 func (sdtMap Map) GetInt8(key string) (val int8, err error) { 257 elem, ok := sdtMap[key] 258 if !ok { 259 return 0, &KeyNotFoundError{key} 260 } 261 return getInt8(elem) 262 } 263 264 // GetInt16 retrieves the data at the specified key and attempt to convert the 265 // data into int16 form if necessary. Returns the int16 value of the 266 // field, and one of the following errors if it occurred: 267 // 268 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 269 // 270 // - sdt.FormatConversionError - If the data cannot be converted into int16 form. 271 func (sdtMap Map) GetInt16(key string) (val int16, err error) { 272 elem, ok := sdtMap[key] 273 if !ok { 274 return 0, &KeyNotFoundError{key} 275 } 276 return getInt16(elem) 277 } 278 279 // GetInt32 retrieves the data at the specified key and attempt to convert the 280 // data into int32 form if necessary. Returns the int32 value of the 281 // field, and one of the following errors if it occurred: 282 // 283 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 284 // 285 // - sdt.FormatConversionError - If the data cannot be converted into int32 form. 286 func (sdtMap Map) GetInt32(key string) (val int32, err error) { 287 elem, ok := sdtMap[key] 288 if !ok { 289 return 0, &KeyNotFoundError{key} 290 } 291 return getInt32(elem) 292 } 293 294 // GetInt64 retrieves the data at the specified key and attempt to convert the 295 // data into int64 form if necessary. Returns the int64 value of the 296 // field, and one of the following errors if it occurred: 297 // 298 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 299 // 300 // - sdt.FormatConversionError - If the data cannot be converted into int64 form. 301 func (sdtMap Map) GetInt64(key string) (val int64, err error) { 302 elem, ok := sdtMap[key] 303 if !ok { 304 return 0, &KeyNotFoundError{key} 305 } 306 return getInt64(elem) 307 } 308 309 // GetUInt8 retrieves the data at the specified key and attempt to convert the 310 // data into uint8 form if necessary. Returns the uint8 value of the 311 // field, and one of the following errors if it occurred: 312 // 313 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 314 // 315 // - sdt.FormatConversionError - If the data cannot be converted into uint8 form. 316 func (sdtMap Map) GetUInt8(key string) (val uint8, err error) { 317 elem, ok := sdtMap[key] 318 if !ok { 319 return 0, &KeyNotFoundError{key} 320 } 321 return getUint8(elem) 322 } 323 324 // GetUInt16 retrieves the data at the specified key and attempt to convert the 325 // data into uint16 form if necessary. Returns the uint16 value of the 326 // field, and one of the following errors if it occurred: 327 // 328 // - sdt.KeyNotFoundError if a mapping for the specified key was not found. 329 // 330 // - sdt.FormatConversionError - If the data cannot be converted into uint16 form. 331 func (sdtMap Map) GetUInt16(key string) (val uint16, err error) { 332 elem, ok := sdtMap[key] 333 if !ok { 334 return 0, &KeyNotFoundError{key} 335 } 336 return getUint16(elem) 337 } 338 339 // GetUInt32 retrieves the data at the specified key and attempt to convert the 340 // data into uint32 form if necessary. Returns the uint32 value of the 341 // field, and one of the following errors if it occurred: 342 // 343 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 344 // 345 // - sdt.FormatConversionError if the data cannot be converted into uint32 form. 346 func (sdtMap Map) GetUInt32(key string) (val uint32, err error) { 347 elem, ok := sdtMap[key] 348 if !ok { 349 return 0, &KeyNotFoundError{key} 350 } 351 return getUint32(elem) 352 } 353 354 // GetUInt64 retrieves the data at the specified key and attempt to convert the 355 // data into uint64 form if necessary. Returns the uint64 value of the 356 // field, and one of the following errors if it occurred: 357 // 358 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 359 // 360 // - sdt.FormatConversionError - If the data cannot be converted into uint64 form 361 func (sdtMap Map) GetUInt64(key string) (val uint64, err error) { 362 elem, ok := sdtMap[key] 363 if !ok { 364 return 0, &KeyNotFoundError{key} 365 } 366 return getUint64(elem) 367 } 368 369 // GetFloat32 retrieves the data at the specified key and attempt to convert the 370 // data into float32 form if necessary. Returns the float32 value of the 371 // field, and one of the following errors if it occurred: 372 // 373 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 374 // 375 // - sdt.FormatConversionError - If the data cannot be converted into float32 form. 376 func (sdtMap Map) GetFloat32(key string) (val float32, err error) { 377 elem, ok := sdtMap[key] 378 if !ok { 379 return 0, &KeyNotFoundError{key} 380 } 381 return getFloat32(elem) 382 } 383 384 // GetFloat64 retrieves the data at the specified key and attempt to convert the 385 // data into float64 form if necessary. Returns the float64 value of the 386 // field, and one of the following errors if it occurred: 387 // 388 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 389 // 390 // - sdt.FormatConversionError - If the data cannot be converted into float64 form. 391 func (sdtMap Map) GetFloat64(key string) (val float64, err error) { 392 elem, ok := sdtMap[key] 393 if !ok { 394 return 0, &KeyNotFoundError{key} 395 } 396 return getFloat64(elem) 397 } 398 399 // GetString retrieves the data at the specified key and attempt to convert the 400 // data into string form if necessary. Returns the string value of the 401 // field, and one of the following errors if it occurred: 402 // 403 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 404 // 405 // - sdt.FormatConversionError - If the data cannot be converted into string form. 406 func (sdtMap Map) GetString(key string) (val string, err error) { 407 elem, ok := sdtMap[key] 408 if !ok { 409 return "", &KeyNotFoundError{key} 410 } 411 return getString(elem) 412 } 413 414 // GetWChar retrieves the data at the specified key and attempt to convert the 415 // data into WChar form if necessary. Returns the WChar value of the 416 // field, and one of the following errors if it occurred: 417 // 418 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 419 // 420 // - sdt.FormatConversionError - If the data cannot be converted into WChar form. 421 func (sdtMap Map) GetWChar(key string) (val WChar, err error) { 422 elem, ok := sdtMap[key] 423 if !ok { 424 return WChar(0), &KeyNotFoundError{key} 425 } 426 return getWChar(elem) 427 } 428 429 // GetByteArray retrieves the data at the specified key and attempt to convert the 430 // data into []byte form if necessary. Returns the []byte value of the 431 // field, and one of the following errors if it occurred: 432 // 433 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 434 // 435 // - sdt.FormatConversionError - If the data cannot be converted into []byte form. 436 func (sdtMap Map) GetByteArray(key string) (val []byte, err error) { 437 elem, ok := sdtMap[key] 438 if !ok { 439 return nil, &KeyNotFoundError{key} 440 } 441 return getByteArray(elem) 442 } 443 444 // GetMap retrieves the data at the specified key as an sdt.Map. 445 // One of the following errors may occur: 446 // 447 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 448 // 449 // - sdt.FormatConversionError - If the data is not of type sdt.Map. 450 func (sdtMap Map) GetMap(key string) (val Map, err error) { 451 elem, ok := sdtMap[key] 452 if !ok { 453 return nil, &KeyNotFoundError{key} 454 } 455 return getMap(elem) 456 } 457 458 // GetStream retrieves the data at the specified key as an sdt.Stream. One of the following errors may occur: 459 // 460 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 461 // 462 // - sdt.FormatConversionError - If the data is not of type sdt.Stream. 463 func (sdtMap Map) GetStream(key string) (val Stream, err error) { 464 elem, ok := sdtMap[key] 465 if !ok { 466 return nil, &KeyNotFoundError{key} 467 } 468 return getStream(elem) 469 } 470 471 // GetDestination retrieves the data at the specified key as a Destination. 472 // One of the following errors may occur: 473 // 474 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 475 // 476 // - sdt.FormatConversionError - If the data is not of type Destination. 477 func (sdtMap Map) GetDestination(key string) (val resource.Destination, err error) { 478 elem, ok := sdtMap[key] 479 if !ok { 480 return nil, &KeyNotFoundError{key} 481 } 482 return getDestination(elem) 483 } 484 485 // GetQueue retrieves the data at the specified key as a Queue. 486 // One of the following errors may occur: 487 // 488 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 489 // 490 // - sdt.FormatConversionError - If the data is not of type Queue. 491 func (sdtMap Map) GetQueue(key string) (val *resource.Queue, err error) { 492 elem, ok := sdtMap[key] 493 if !ok { 494 return nil, &KeyNotFoundError{key} 495 } 496 return getQueue(elem) 497 } 498 499 // GetTopic retrieves the data at the specified key as a Topic. 500 // One of the following errors may occur: 501 // 502 // - sdt.KeyNotFoundError - If a mapping for the specified key was not found. 503 // 504 // - sdt.FormatConversionError - If the data is not of type Topic. 505 func (sdtMap Map) GetTopic(key string) (val *resource.Topic, err error) { 506 elem, ok := sdtMap[key] 507 if !ok { 508 return nil, &KeyNotFoundError{key} 509 } 510 return getTopic(elem) 511 } 512 513 // GetBool retrieves the data at the specified index and attempt to convert the 514 // data into boolean form if necessary. Returns the boolean value of the 515 // field, and one of the following errors if it occurred: 516 // 517 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 518 // 519 // - sdt.FormatConversionError - If the data cannot be converted into boolean form. 520 func (sdtStream Stream) GetBool(index int) (val bool, err error) { 521 if index >= len(sdtStream) || index < 0 { 522 return false, &OutOfBoundsError{Index: index} 523 } 524 return getBool(sdtStream[index]) 525 } 526 527 // GetByte retrieves the data at the specified index and attempt to convert the 528 // data into byte form if necessary. Returns the byte value of the field, 529 // and one of the following errors if it occurred: 530 // 531 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 532 // 533 // - sdt.FormatConversionError - If the data cannot be converted into byte form. 534 func (sdtStream Stream) GetByte(index int) (val byte, err error) { 535 if index >= len(sdtStream) || index < 0 { 536 return 0, &OutOfBoundsError{Index: index} 537 } 538 return getUint8(sdtStream[index]) 539 } 540 541 // GetInt retrieves the data at the specified index and attempt to convert the 542 // data into int form if necessary. Returns the int value of the 543 // field, and one of the following errors if it occurred: 544 // 545 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 546 // 547 // - sdt.FormatConversionError - If the data cannot be converted into int form. 548 func (sdtStream Stream) GetInt(index int) (val int, err error) { 549 if index >= len(sdtStream) || index < 0 { 550 return 0, &OutOfBoundsError{Index: index} 551 } 552 return getInt(sdtStream[index]) 553 } 554 555 // GetUInt retrieves the data at the specified index and attempt to convert the 556 // data into uint form if necessary. Returns the uint value of the 557 // field, and one of the following errors if it occurred: 558 // 559 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 560 // 561 // - sdt.FormatConversionError - If the data cannot be converted into uint form. 562 func (sdtStream Stream) GetUInt(index int) (val uint, err error) { 563 if index >= len(sdtStream) || index < 0 { 564 return 0, &OutOfBoundsError{Index: index} 565 } 566 return getUint(sdtStream[index]) 567 } 568 569 // GetInt8 retrieves the data at the specified index and attempt to convert the 570 // data into int8 form if necessary. Returns the int8 value of the 571 // field, and one of the following errors if it occurred: 572 // 573 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 574 // 575 // - sdt.FormatConversionError - If the data cannot be converted into int8 form. 576 func (sdtStream Stream) GetInt8(index int) (val int8, err error) { 577 if index >= len(sdtStream) || index < 0 { 578 return 0, &OutOfBoundsError{Index: index} 579 } 580 return getInt8(sdtStream[index]) 581 } 582 583 // GetInt16 retrieves the data at the specified index and attempt to convert the 584 // data into int16 form if necessary. Returns the int16 value of the 585 // field, and one of the following errors if it occurred: 586 // 587 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 588 // 589 // - sdt.FormatConversionError - If the data cannot be converted into int16 form. 590 func (sdtStream Stream) GetInt16(index int) (val int16, err error) { 591 if index >= len(sdtStream) || index < 0 { 592 return 0, &OutOfBoundsError{Index: index} 593 } 594 return getInt16(sdtStream[index]) 595 } 596 597 // GetInt32 retrieves the data at the specified index and attempt to convert the 598 // data into int32 form if necessary. Returns the int32 value of the 599 // field, and one of the following errors if it occurred: 600 // 601 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 602 // 603 // - sdt.FormatConversionError - If the data cannot be converted into int32 form. 604 func (sdtStream Stream) GetInt32(index int) (val int32, err error) { 605 if index >= len(sdtStream) || index < 0 { 606 return 0, &OutOfBoundsError{Index: index} 607 } 608 return getInt32(sdtStream[index]) 609 } 610 611 // GetInt64 retrieves the data at the specified index and attempt to convert the 612 // data into int64 form if necessary. Returns the int64 value of the 613 // field, and one of the following errors if it occurred: 614 // 615 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 616 // 617 // - sdt.FormatConversionError - If the data cannot be converted into int64 form. 618 func (sdtStream Stream) GetInt64(index int) (val int64, err error) { 619 if index >= len(sdtStream) || index < 0 { 620 return 0, &OutOfBoundsError{Index: index} 621 } 622 return getInt64(sdtStream[index]) 623 } 624 625 // GetUInt8 retrieves the data at the specified index and attempt to convert the 626 // data into uint8 form if necessary. Returns the uint8 value of the 627 // field, and one of the following errors if it occurred: 628 // 629 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 630 // 631 // - sdt.FormatConversionError - If the data cannot be converted into uint8 form. 632 func (sdtStream Stream) GetUInt8(index int) (val uint8, err error) { 633 if index >= len(sdtStream) || index < 0 { 634 return 0, &OutOfBoundsError{Index: index} 635 } 636 return getUint8(sdtStream[index]) 637 } 638 639 // GetUInt16 retrieves the data at the specified index and attempt to convert the 640 // data into uint16 form if necessary. Returns the uint16 value of the 641 // field, and one of the following errors if it occurred: 642 // 643 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 644 // 645 // - sdt.FormatConversionError - If the data cannot be converted into uint16 form. 646 func (sdtStream Stream) GetUInt16(index int) (val uint16, err error) { 647 if index >= len(sdtStream) || index < 0 { 648 return 0, &OutOfBoundsError{Index: index} 649 } 650 return getUint16(sdtStream[index]) 651 } 652 653 // GetUInt32 retrieves the data at the specified index and attempt to convert the 654 // data into uint32 form if necessary. Returns the uint32 value of the 655 // field, and one of the following errors if it occurred: 656 // 657 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 658 // 659 // - sdt.FormatConversionError - If the data cannot be converted into uint32 form. 660 func (sdtStream Stream) GetUInt32(index int) (val uint32, err error) { 661 if index >= len(sdtStream) || index < 0 { 662 return 0, &OutOfBoundsError{Index: index} 663 } 664 return getUint32(sdtStream[index]) 665 } 666 667 // GetUInt64 retrieves the data at the specified index and attempt to convert the 668 // data into uint64 form if necessary. Returns the uint64 value of the 669 // field, and one of the following errors if it occurred: 670 // 671 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 672 // 673 // - sdt.FormatConversionError - If the data cannot be converted into uint64 form. 674 func (sdtStream Stream) GetUInt64(index int) (val uint64, err error) { 675 if index >= len(sdtStream) || index < 0 { 676 return 0, &OutOfBoundsError{Index: index} 677 } 678 return getUint64(sdtStream[index]) 679 } 680 681 // GetFloat32 retrieves the data at the specified index and attempt to convert the 682 // data into float32 form if necessary. Returns the float32 value of the 683 // field, and one of the following errors if it occurred: 684 // 685 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 686 // 687 // - sdt.FormatConversionError - If the data cannot be converted into float32 form. 688 func (sdtStream Stream) GetFloat32(index int) (val float32, err error) { 689 if index >= len(sdtStream) || index < 0 { 690 return 0, &OutOfBoundsError{Index: index} 691 } 692 return getFloat32(sdtStream[index]) 693 } 694 695 // GetFloat64 retrieves the data at the specified index and attempt to convert the 696 // data into float64 form if necessary. Returns the float64 value of the 697 // field, and one of the following errors if it occurred: 698 // 699 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 700 // 701 // - sdt.FormatConversionError - If the data cannot be converted into float64 form. 702 func (sdtStream Stream) GetFloat64(index int) (val float64, err error) { 703 if index >= len(sdtStream) || index < 0 { 704 return 0, &OutOfBoundsError{Index: index} 705 } 706 return getFloat64(sdtStream[index]) 707 } 708 709 // GetString retrieves the data at the specified index and attempt to convert the 710 // data into string form if necessary. Returns the string value of the 711 // field, and one of the following errors if it occurred: 712 // 713 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 714 // 715 // - sdt.FormatConversionError - If the data cannot be converted into string form. 716 func (sdtStream Stream) GetString(index int) (val string, err error) { 717 if index >= len(sdtStream) || index < 0 { 718 return "", &OutOfBoundsError{Index: index} 719 } 720 return getString(sdtStream[index]) 721 } 722 723 // GetWChar retrieves the data at the specified index and attempt to convert the 724 // data into WChar form if necessary. Returns the WChar value of the 725 // field, and one of the following errors if it occurred: 726 // 727 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 728 // 729 // - sdt.FormatConversionError - If the data cannot be converted into WChar form. 730 func (sdtStream Stream) GetWChar(index int) (val WChar, err error) { 731 if index >= len(sdtStream) || index < 0 { 732 return WChar(0), &OutOfBoundsError{Index: index} 733 } 734 return getWChar(sdtStream[index]) 735 } 736 737 // GetByteArray retrieves the data at the specified index and attempt to convert the 738 // data into []byte form if necessary. Returns the []byte value of the 739 // field, and one of the following errors if it occurred: 740 // 741 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 742 // 743 // - sdt.FormatConversionError - If the data cannot be converted into []byte form. 744 func (sdtStream Stream) GetByteArray(index int) (val []byte, err error) { 745 if index >= len(sdtStream) || index < 0 { 746 return nil, &OutOfBoundsError{Index: index} 747 } 748 return getByteArray(sdtStream[index]) 749 } 750 751 // GetMap retrieves the data at the specified index as an sdt.Map. 752 // One of the following errors may occur: 753 // 754 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 755 // 756 // - sdt.FormatConversionError - If the data is not of type sdt.Map. 757 func (sdtStream Stream) GetMap(index int) (val Map, err error) { 758 if index >= len(sdtStream) || index < 0 { 759 return nil, &OutOfBoundsError{Index: index} 760 } 761 return getMap(sdtStream[index]) 762 } 763 764 // GetStream retrieves the data at the specified index as an sdt.Stream. 765 // One of the following errors may occur: 766 // 767 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 768 // 769 // - sdt.FormatConversionError - If the data is not of type sdt.Stream. 770 func (sdtStream Stream) GetStream(index int) (val Stream, err error) { 771 if index >= len(sdtStream) || index < 0 { 772 return nil, &OutOfBoundsError{Index: index} 773 } 774 return getStream(sdtStream[index]) 775 } 776 777 // GetDestination retrieves the data at the specified index as a Destination. 778 // One of the following errors may occur: 779 // 780 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 781 // 782 // - sdt.FormatConversionError - If the data is not of type Destination. 783 func (sdtStream Stream) GetDestination(index int) (val resource.Destination, err error) { 784 if index >= len(sdtStream) || index < 0 { 785 return nil, &OutOfBoundsError{Index: index} 786 } 787 return getDestination(sdtStream[index]) 788 } 789 790 // GetQueue retrieves the data at the specified index as a Queue. 791 // One of the following errors may occur: 792 // 793 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 794 // 795 // - sdt.FormatConversionError - If the data is not of type Queue. 796 func (sdtStream Stream) GetQueue(index int) (val *resource.Queue, err error) { 797 if index >= len(sdtStream) || index < 0 { 798 return nil, &OutOfBoundsError{Index: index} 799 } 800 return getQueue(sdtStream[index]) 801 } 802 803 // GetTopic retrieves the data at the specified index as a Topic. 804 // One of the following errors may occur: 805 // 806 // - sdt.OutOfBoundsError - If the specified index is out of the stream's bounds. 807 // 808 // - sdt.FormatConversionError - If the data is not of type Topic. 809 func (sdtStream Stream) GetTopic(index int) (val *resource.Topic, err error) { 810 if index >= len(sdtStream) || index < 0 { 811 return nil, &OutOfBoundsError{Index: index} 812 } 813 return getTopic(sdtStream[index]) 814 } 815 816 func getBool(elem interface{}) (bool, error) { 817 switch casted := elem.(type) { 818 case bool: 819 return casted, nil 820 case int: 821 return casted != 0, nil 822 case uint: 823 return casted != 0, nil 824 case uint8: 825 return casted != 0, nil 826 case int8: 827 return casted != 0, nil 828 case uint16: 829 return casted != 0, nil 830 case int16: 831 return casted != 0, nil 832 case uint32: 833 return casted != 0, nil 834 case int32: 835 return casted != 0, nil 836 case uint64: 837 return casted != 0, nil 838 case int64: 839 return casted != 0, nil 840 case string: 841 if casted == "true" || casted == "1" { 842 return true, nil 843 } else if casted == "false" || casted == "0" { 844 return false, nil 845 } 846 return false, &FormatConversionError{ 847 fmt.Sprintf("cannot convert string '%s' to bool", casted), 848 casted, 849 } 850 // case []byte: 851 // case float32: 852 // case float64: 853 // case WChar: 854 default: 855 return false, defaultFormatConversionError(elem, "bool") 856 } 857 } 858 859 func getUint8(elem interface{}) (uint8, error) { 860 converted, err := parseUint(elem, 8) 861 if err != nil { 862 return 0, err 863 } 864 return uint8(converted), nil 865 } 866 867 func getInt8(elem interface{}) (int8, error) { 868 converted, err := parseInt(elem, 8) 869 if err != nil { 870 return 0, err 871 } 872 return int8(converted), nil 873 } 874 875 func getUint16(elem interface{}) (uint16, error) { 876 converted, err := parseUint(elem, 16) 877 if err != nil { 878 return 0, err 879 } 880 return uint16(converted), nil 881 } 882 883 func getInt16(elem interface{}) (int16, error) { 884 converted, err := parseInt(elem, 16) 885 if err != nil { 886 return 0, err 887 } 888 return int16(converted), nil 889 } 890 891 func getUint32(elem interface{}) (uint32, error) { 892 converted, err := parseUint(elem, 32) 893 if err != nil { 894 return 0, err 895 } 896 return uint32(converted), nil 897 } 898 899 func getInt32(elem interface{}) (int32, error) { 900 converted, err := parseInt(elem, 32) 901 if err != nil { 902 return 0, err 903 } 904 return int32(converted), nil 905 } 906 907 func getUint64(elem interface{}) (uint64, error) { 908 converted, err := parseUint(elem, 64) 909 if err != nil { 910 return 0, err 911 } 912 return uint64(converted), nil 913 } 914 915 func getInt64(elem interface{}) (int64, error) { 916 converted, err := parseInt(elem, 64) 917 if err != nil { 918 return 0, err 919 } 920 return int64(converted), nil 921 } 922 923 var uintSize = 8 * int(unsafe.Sizeof(uint(0))) 924 925 func getUint(elem interface{}) (uint, error) { 926 converted, err := parseUint(elem, uintSize) 927 if err != nil { 928 return 0, err 929 } 930 return uint(converted), nil 931 } 932 933 var intSize = 8 * int(unsafe.Sizeof(int(0))) 934 935 func getInt(elem interface{}) (int, error) { 936 converted, err := parseInt(elem, intSize) 937 if err != nil { 938 return 0, err 939 } 940 return int(converted), nil 941 } 942 943 func parseInt(elem interface{}, bits int) (int64, error) { 944 switch casted := elem.(type) { 945 case bool: 946 if casted { 947 return 1, nil 948 } 949 return 0, nil 950 case []byte, float32, float64, WChar: 951 goto conversionErr 952 case int, uint, int8, int16, int32, int64, uint8, uint16, uint32, uint64: 953 goto fromString 954 case string: 955 goto fromString 956 default: 957 goto conversionErr 958 } 959 conversionErr: 960 return 0, defaultFormatConversionError(elem, fmt.Sprintf("int%d", bits)) 961 fromString: 962 str := fmt.Sprint(elem) 963 i, err := strconv.ParseInt(str, 10, bits) 964 if err != nil { 965 return 0, nestedFormatConversionError(elem, fmt.Sprintf("int%d", bits), err) 966 } 967 return int64(i), nil 968 } 969 970 func parseUint(elem interface{}, bits int) (uint64, error) { 971 switch casted := elem.(type) { 972 case bool: 973 if casted { 974 return 1, nil 975 } 976 return 0, nil 977 978 case []byte, float32, float64, WChar: 979 goto conversionErr 980 case int, uint, int8, int16, int32, int64, uint8, uint16, uint32, uint64: 981 goto fromString 982 case string: 983 goto fromString 984 default: 985 goto conversionErr 986 } 987 conversionErr: 988 return 0, defaultFormatConversionError(elem, fmt.Sprintf("uint%d", bits)) 989 fromString: 990 str := fmt.Sprint(elem) 991 i, err := strconv.ParseUint(str, 10, bits) 992 if err != nil { 993 return 0, nestedFormatConversionError(elem, fmt.Sprintf("uint%d", bits), err) 994 } 995 return uint64(i), nil 996 } 997 998 func getByteArray(elem interface{}) ([]byte, error) { 999 switch casted := elem.(type) { 1000 case []byte: 1001 return casted, nil 1002 case string: 1003 return []byte(casted), nil 1004 default: 1005 return nil, defaultFormatConversionError(elem, "[]uint8") 1006 } 1007 } 1008 1009 func getFloat32(elem interface{}) (float32, error) { 1010 const typeString = "float32" 1011 switch casted := elem.(type) { 1012 case float32: 1013 return casted, nil 1014 case string: 1015 f, err := strconv.ParseFloat(casted, 32) 1016 if err != nil { 1017 return 0, nestedFormatConversionError(casted, typeString, err) 1018 } 1019 return float32(f), nil 1020 default: 1021 return 0, defaultFormatConversionError(elem, typeString) 1022 } 1023 } 1024 1025 func getFloat64(elem interface{}) (float64, error) { 1026 const typeString = "float64" 1027 switch casted := elem.(type) { 1028 case float64: 1029 return casted, nil 1030 case string: 1031 f, err := strconv.ParseFloat(casted, 64) 1032 if err != nil { 1033 return 0, nestedFormatConversionError(casted, typeString, err) 1034 } 1035 return f, nil 1036 default: 1037 return 0, defaultFormatConversionError(elem, typeString) 1038 } 1039 } 1040 1041 func getString(elem interface{}) (string, error) { 1042 switch casted := elem.(type) { 1043 case string: 1044 return casted, nil 1045 default: 1046 return "", defaultFormatConversionError(elem, "string") 1047 } 1048 } 1049 1050 func getWChar(elem interface{}) (WChar, error) { 1051 switch casted := elem.(type) { 1052 case uint8: 1053 return WChar(casted), nil 1054 case int8: 1055 return WChar(casted), nil 1056 case WChar: 1057 return casted, nil 1058 case string: 1059 if len(casted) == 1 { 1060 return WChar(casted[0]), nil 1061 } 1062 return 0, &FormatConversionError{fmt.Sprintf("cannot convert string of length %d to sdt.WChar", len(casted)), casted} 1063 default: 1064 return 0, defaultFormatConversionError(elem, "sdt.WChar") 1065 } 1066 } 1067 1068 func getMap(elem interface{}) (Map, error) { 1069 if casted, ok := elem.(Map); ok { 1070 return casted, nil 1071 } 1072 return nil, defaultFormatConversionError(elem, "sdt.Map") 1073 } 1074 1075 func getStream(elem interface{}) (Stream, error) { 1076 if casted, ok := elem.(Stream); ok { 1077 return casted, nil 1078 } 1079 return nil, defaultFormatConversionError(elem, "sdt.Stream") 1080 } 1081 1082 func getQueue(elem interface{}) (*resource.Queue, error) { 1083 if casted, ok := elem.(*resource.Queue); ok { 1084 return casted, nil 1085 } 1086 return nil, defaultFormatConversionError(elem, "*resource.Queue") 1087 } 1088 1089 func getTopic(elem interface{}) (*resource.Topic, error) { 1090 if casted, ok := elem.(*resource.Topic); ok { 1091 return casted, nil 1092 } 1093 return nil, defaultFormatConversionError(elem, "*resource.Topic") 1094 } 1095 1096 func getDestination(elem interface{}) (resource.Destination, error) { 1097 if casted, ok := elem.(resource.Destination); ok { 1098 return casted, nil 1099 } 1100 return nil, defaultFormatConversionError(elem, "resource.Destination") 1101 } 1102