How to serialize slice of fixed length data structure in Go - go

The following code generates panic: binary.Write: invalid type main.test:
type (
config struct {
Key uint16
Val uint16
}
test struct {
Mode uint32
Data []config
}
)
func main() {
t := test{
Mode: 5,
Data: []config{
{1, 2},
{3, 4},
},
}
var bs bytes.Buffer
assert(binary.Write(&bs, binary.LittleEndian, t))
}
The key point is:
length of the config data structure is fixed, but the test structure contains a slice of config, whose number varies.
I need to interact with other program written in C, so cannot use things like GOB.
Is there anyway to binary-encode such data structure, apart from do it manually?

The problem is not writing out a slice, as slices are supported. Quoting from binary.Write():
Write writes the binary representation of data into w. Data must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
The problem is that the size of config is not fixed. It is not fixed because it contains a field of slice type, and the binary representation of the slice is not fixed (depends on its length).
So writing a slice value is supported, writing a value of composite type (e.g. struct) holding a slice is not supported for the above mentioned reason.
You may change the field to an array type (e.g. [2]config) but I assume this isn't sufficient to you.
You may write the fields using encoding/binary individually, in which case you can write a slice value.
For example:
var bs bytes.Buffer
fmt.Println(binary.Write(&bs, binary.LittleEndian, t.Mode))
fmt.Println(binary.Write(&bs, binary.LittleEndian, t.Data))
This will output (try it on the Go Playground):
<nil>
<nil>
There was a proposal to extend encoding/binary to support similar cases (see here), but was rejected. encoding/binary is for simple things.
If you need more flexibility, use encoding/gob (although Go specific), or use encoding/json (supported by all languages).

Related

Go vet reports "possible misuse of reflect.SliceHeader"

I have the following code snippet which "go vet" complains about with the warning "possible misuse of reflect.SliceHeader". I can not find very much information about this warning other then this. After reading that it is not very clear to me what is needed to do this in a way that makes go vet happy - and without possible gc issues.
The goal of the snippet is to have a go function copy data to memory which is managed by an opaque C library. The Go function expects a []byte as a parameter.
func Callback(ptr unsafe.Pointer, buffer unsafe.Pointer, size C.longlong) C.longlong {
...
sh := &reflect.SliceHeader{
Data: uintptr(buffer),
Len: int(size),
Cap: int(size),
}
buf := *(*[]byte)(unsafe.Pointer(sh))
err := CopyToSlice(buf)
if err != nil {
log.Fatal("failed to copy to slice")
}
...
}
https://pkg.go.dev/unsafe#go1.19.4#Pointer
Pointer represents a pointer to an arbitrary type. There are four
special operations available for type Pointer that are not available
for other types:
A pointer value of any type can be converted to a Pointer.
A Pointer can be converted to a pointer value of any type.
A uintptr can be converted to a Pointer.
A Pointer can be converted to a uintptr.
Pointer therefore allows a program to defeat the type system and read
and write arbitrary memory. It should be used with extreme care.
The following patterns involving Pointer are valid. Code not using
these patterns is likely to be invalid today or to become invalid in
the future. Even the valid patterns below come with important caveats.
Running "go vet" can help find uses of Pointer that do not conform to
these patterns, but silence from "go vet" is not a guarantee that the
code is valid.
(6) Conversion of a reflect.SliceHeader or reflect.StringHeader Data
field to or from Pointer.
As in the previous case, the reflect data structures SliceHeader and
StringHeader declare the field Data as a uintptr to keep callers from
changing the result to an arbitrary type without first importing
"unsafe". However, this means that SliceHeader and StringHeader are
only valid when interpreting the content of an actual slice or string
value.
var s string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) // case 1
hdr.Data = uintptr(unsafe.Pointer(p)) // case 6 (this case)
hdr.Len = n
In this usage hdr.Data is really an alternate way to refer to the
underlying pointer in the string header, not a uintptr variable
itself.
In general, reflect.SliceHeader and reflect.StringHeader should be used only as *reflect.SliceHeader and *reflect.StringHeader pointing at actual slices or strings, never as plain structs. A program should not declare or allocate variables of these struct types.
// INVALID: a directly-declared header will not hold Data as a reference.
var hdr reflect.StringHeader
hdr.Data = uintptr(unsafe.Pointer(p))
hdr.Len = n
s := *(*string)(unsafe.Pointer(&hdr)) // p possibly already lost
It looks like JimB (from the comments) hinted upon the most correct answer, though he didn't post it as an answer and he didn't include an example. The following passes go vet, staticcheck, and golangci-lint - and doesn't segfault so I think it is the correct answer.
func Callback(ptr unsafe.Pointer, buffer unsafe.Pointer, size C.longlong) C.longlong {
...
buf := unsafe.Slice((*byte)(buffer), size)
err := CopyToSlice(buf)
if err != nil {
log.Fatal("failed to copy to slice")
}
...
}

Why can I not use an slice of a custom type as an empty interface slice when using append in Go? [duplicate]

This question already has answers here:
Type converting slices of interfaces
(9 answers)
Cannot convert []string to []interface {}
(7 answers)
Cannot use args (type []string) as type []interface {} [duplicate]
(1 answer)
slice of struct != slice of interface it implements?
(6 answers)
Closed 4 months ago.
I'm slightly confused about the behavior of the unpack/spread operator when trying to append into a slice of empty interfaces (i.e. []interface{}) from an slice of a custom type. I expected it to work since the interface{} can hold any type, but I'm currently receiving errors when trying to do this operation.
The following snippet illustrates the issue:
package main
import (
"fmt"
)
type CustomType struct {
value int
}
func main() {
data := []interface{}{}
values := []CustomType{
{value: 0},
{value: 1},
}
// This does not compile:
// data = append(data, values...)
// But this works fine
data = append(data, values[0])
for _, value := range data {
fmt.Printf("Value: %v\n", value)
}
}
Go playground with the snippet above
I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type. When I append the values one by one, then compiler is OK with the operation.
Why is unpacking the values slice not allowed in this situation?
Obviously, the code data = append(data, values...) could be compiled error cannot use values (variable of type []CustomType) as type []interface{} in argument to append
Per faq Can I convert a []T to an []interface{}?
Not directly. It is disallowed by the language specification because the two types do not have the same representation in memory. It is necessary to copy the elements individually to the destination slice. This example converts a slice of int to a slice of interface{}:
t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
s[i] = v
}
For your question
I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type.
The difference between the element type CustomType and interface
type CustomType represented in memory like value
type interface{} represented in memory
pointer to type CustomType
value
They have different representations in memory.
Besides that, converting a []CustomType to an []interface{} is O(n) time because each value of the slice must be converted to an interface{}. It could be one complex operation.

function that accepts *[128]uint8, *[256]uint8 etc

In my code I have :
fmt.Printf("event.Comm type: %T\n", event.Comm)
fmt.Printf("&event.Comm type: %T\n", &event.Comm)
Which prints:
event.Comm type: [128]uint8
&event.Comm type: *[128]uint8
event.Comm type: [256]uint8
&event.Comm type: *[256]uint8
and so on.
I would like to define a function where I can pass their pointers, and get some work done.
so I defined:
func aux(x *[]byte){
fmt.Println("Aux got", x)
}
hoping that I'd send aux(&event.Comm) and aux(&trigger.Comm) et al.
Except that it refused to build:
cannot use &event.Comm (type *[128]byte) as type *[]byte in argument to aux
What's the idiomatic way to define a function signature with *[n]uint8 as its arguments?
The idiomatic approach is to use a slice:
func aux(x []byte){
fmt.Println("Aux got", x)
}
Use the slice expression [:] to create a slice backed by the array:
aux(event.Comm[:])
Note that arrays and slices are different types and are not assignable to each other. Arrays have a fixed size. A slice describes a section of an array. A slice header contains a pointer to the backing array, the length of the slice and the capacity of the backing array.
[128]byte is an array type. []byte is a slice type. They aren't the same type and there's no implicit conversion from one to the other. Your sample code doesn't make it clear what aux is actually supposed to do, but at a guess you should change aux to accept a []byte (pointers to slices are hardly ever necessary), and call it like aux(event.Comm[:]). [:] is a slice expression which creates a slice with a view of the whole array.
The type of the event is fixed sized array of [128]byte but in the argument of the aux you are passing the slice. The error was explaining the issue pretty well. In order to solve the error you need to define the size of the slice so your code should be like this.
package main
import "fmt"
func aux(x *[128]byte) {
fmt.Println("Aux got", x)
}
func main() {
var Comm [128]uint8
aux(&Comm)
}
or you can convert the array type to slice as hobbs explained in his answer.

Go deserialization when type is not known

I'm writing a package in go to send messages between services, using a specific type of transport.
I'd like the package to not understand the type of messages being sent.
My first thought is to serialize the message object into json, send that, deserialize on the receiving end, and pass the go object (as an interface{}) to the subscribing code.
The serialization isn't a problem, but I don't see how the generic package code can deserialize the message since it doesn't know the type. I thought of using reflect TypeOf(), and passing that value as part of the message. But I don't see how to accomplish this since Type is an interface and the implementing rtype is not exported.
If the receiving app gets an interface{}, it is going to have to check the type anyways, so maybe it should just do the deserialization. Or the receiver could provide a reflect Type so the package can deserialize?
Or it could give the receiver a map of field name to value, but I'd prefer the actual type.
Any suggestions?
Let me add an example:
I have a go channel for sending change notifications of different types of objects. Since go doesn't support tagged unions, I define the channel type as:
type UpdateInfo struct {
UpdateType UpdateType
OldObject interface{}
NewObject interface{}
}
The receiving end of the channel gets an UpdateInfo with OldObject and NewObject as the actual concrete object types that were sent.
I want to extend this to work between applications, where the transport will be via a message queue to support pub/sub, multiple consumers, etc.
TL;DR
Just use json.Unmarshal. You can wrap it lightly, using your transport, and call json.Unmarshal (or with a json.Decoder instance, use d.Decode) on your prebuilt JSON bytes and the v interface{} argument from your caller.
Somewhat longer, with an example
Consider how json.Unmarshal does its own magic. Its first argument is the JSON (data []byte), but its second argument is of type interface{}:
func Unmarshal(data []byte, v interface{}) error
As the documentation goes on to say, if v really is just an interface{}:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
but if v has an underlying concrete type, such as type myData struct { ... }, it's much fancier. It only does the above if v's underlying type is interface{}.
Its actual implementation is particularly complex because it's optimized to do the de-JSON-ification and the assignment into the target object at the same time. In principle, though, it's mostly a big type-switch on the underlying (concrete) type of the interface value.
Meanwhile, what you are describing in your question is that you will first deserialize into generic JSON—which really means a variable of type interface{}—and then do your own assignment out of this pre-decoded JSON into another variable of type interface{}, where the type signature of your own decoder would be:
func xxxDecoder(/* maybe some args here, */ v interface{}) error {
var predecoded interface{}
// get some json bytes from somewhere into variable `data`
err := json.Unmarshal(data, &predecoded)
// now emulate json.Unmarshal by getting field names and assigning
... this is the hard part ...
}
and you would then call this code by writing:
type myData struct {
Field1 int `xxx:"Field1"`
Field2 string `xxx:"Field2"`
}
so that you know that JSON object key "Field1" should fill in your Field1 field with an integer, and JSON object key "Field2" should fill in your Field2 field with a string:
func whatever() {
var x myData
err := xxxDecode(..., &x)
if err != nil { ... handle error ... }
... use x.Field1 and x.Field2 ...
}
But this is silly. You can just write:
type myData struct {
Field1 int `json:"Field1"`
Field2 string `json:"Field2"`
}
(or even omit the tags since the field's names are the default json tags), and then do this:
func xxxDecode(..., v interface{}) error {
... get data bytes as before ...
return json.Unmarshal(data, v)
}
In other words, just let json.Unmarshal do all the work by providing json tags in the data structures in question. You still get—and transmit across your special transport—the JSON data bytes from json.Marshal and json.Unmarshal. You do the transmitting and receiving. json.Marshal and json.Unmarshal do all the hard work: you don't have to touch it!
It's still fun to see how Json.Unmarshal works
Jump down to around line 660 of encoding/json/decode.go, where you will find the thing that handles a JSON "object" ({ followed by either } or a string that represents a key), for instance:
func (d *decodeState) object(v reflect.Value) error {
There are some mechanics to handle corner cases (including the fact that v might not be settable and/or might be a pointer that should be followed), then it makes sure that v is either a map[T1]T2 or struct, and if it is a map, that it's suitable—that both T1 and T2 will work when decoding the "key":value items in the object.
If all goes well, it gets into the JSON key-and-value scanning loop starting at line 720 (for {, which will break or return as appropriate). On each trip through this loop, the code reads the JSON key first, leaving the : and value part for later.
If we're decoding into a struct, the decoder now uses the struct's fields—names and json:"..." tags—to find a reflect.Value that we'll use to store right into the field.1 This is subv, found by calling v.Field(i) for the right i, with some slightly complicated goo to handle embedded anonymous structs and pointer-following. The core of this is just subv = v.Field(i), though, where i is whichever field this key names, within the struct. So subv is now a reflect.Value that represents the actual struct instance's value, which we should set once we've decoded the value part of the JSON key-value pair.
If we're decoding into a map, we will decode the value into a temporary first, then store it into the map after decoding. It would be nice to share this with the struct-field storing, but we need a different reflect function to do the store into the map: v.SetMapIndex, where v is the reflect.Value of the map. That's why for a map, subv points to a temporary Elem.
We're now ready to convert the actual value to the target type, so we go back to the JSON bytes and consume the colon : character and read the JSON value. We get the value and store it into our storage location (subv). This is the code starting at line 809 (if destring {). The actual assigning is done through the decoder functions (d.literalStore at line 908, or d.value at line 412) and these actually decode the JSON value while doing the storing. Note that only d.literalStore really stores the value—d.value calls on d.array, d.object, or d.literalStore to do the work recursively if needed.
d.literalStore therefore contains many switch v.Kind()s: it parses a null or a true or false or an integer or a string or an array, then makes sure it can store the resulting value into v.Kind(), and chooses how to store that resulting value into v.Kind() based on the combination of what it just decoded, and the actual v.Kind(). So there's a bit of a combinatorial explosion here, but it gets the job done.
If all that worked, and we're decoding to a map, we may now need to massage the type of the temporary, find the real key, and store the converted value into the map. That's what lines 830 (if v.Kind() == reflect.Map {) through the final close brace at 867 are about.
1To find fields, we first look over at encoding/json/encode.go to find cachedTypeFields. It is a caching version of typeFields. This is where the json tags are found and put into a slice. The result is cached via cachedTypeFields in a map indexed by the reflect-type value of the struct type. So what we get is a slow lookup the first time we use a struct type, then a fast lookup afterwards, to get a slice of information about how to do the decoding. This slice-of-information maps from json-tag-or-field name to: field; type; whether it's a sub-field of an anonymous structure; and so on: everything we will need to know to decode it properly—or to encode it, on the encoding side. (I didn't really look closely at this code.)
You can encode/decode several message on the same buffer, whether that be a "gob" or "json" or some other encoding.
Assuming there's a limited set of concrete types that you want to support, you can always encode a type tag as the first thing, then encode the actual object. This way the decode can decode the type tag first, and depending on its value, decide how to decode the next item.
// encoder side
enc := json.NewEncoder(buffer) // or gob.NewEncoder(buffer)
enc.Encode("player")
enc.Encode(playerInstance)
// decoder side
dec := json.NewDecoder(buffer) // or gob.NewDecoder(buffer)
var tag string
dec.Decode(&tag)
switch tag {
case "player":
var playerInstance Player
dec.Decode(&player)
// do something with it
case "somethingelse":
// decode something else
}
Try dynobuffers instead of struct. It provides get and set by name ability for byte array. Also it is much more faster than json.

Conversion of a slice of string into a slice of custom type

I'm quite new to Go, so this might be obvious. The compiler does not allow the following code:
(http://play.golang.org/p/3sTLguUG3l)
package main
import "fmt"
type Card string
type Hand []Card
func NewHand(cards []Card) Hand {
hand := Hand(cards)
return hand
}
func main() {
value := []string{"a", "b", "c"}
firstHand := NewHand(value)
fmt.Println(firstHand)
}
The error is:
/tmp/sandbox089372356/main.go:15: cannot use value (type []string) as type []Card in argument to NewHand
From the specs, it looks like []string is not the same underlying type as []Card, so the type conversion cannot occur.
Is it, indeed, the case, or did I miss something?
If it is the case, why is it so? Assuming, in a non-pet-example program, I have as input a slice of string, is there any way to "cast" it into a slice of Card, or do I have to create a new structure and copy the data into it? (Which I'd like to avoid since the functions I'll need to call will modify the slice content).
There is no technical reason why conversion between slices whose elements have identical underlying types (such as []string and []Card) is forbidden. It was a specification decision to help avoid accidental conversions between unrelated types that by chance have the same structure.
The safe solution is to copy the slice. However, it is possible to convert directly (without copying) using the unsafe package:
value := []string{"a", "b", "c"}
// convert &value (type *[]string) to *[]Card via unsafe.Pointer, then deref
cards := *(*[]Card)(unsafe.Pointer(&value))
firstHand := NewHand(cards)
https://play.golang.org/p/tto57DERjYa
Obligatory warning from the package documentation:
unsafe.Pointer allows a program to defeat the type system and read and write arbitrary memory. It should be used with extreme care.
There was a discussion on the mailing list about conversions and underlying types in 2011, and a proposal to allow conversion between recursively equivalent types in 2016 which was declined "until there is a more compelling reason".
The underlying type of Card might be the same as the underlying type of string (which is itself: string), but the underlying type of []Card is not the same as the underlying type of []string (and therefore the same applies to Hand).
You cannot convert a slice of T1 to a slice of T2, it's not a matter of what underlying types they have, if T1 is not identical to T2, you just can't. Why? Because slices of different element types may have different memory layout (different size in memory). For example the elements of type []byte occupy 1 byte each. The elements of []int32 occupy 4 bytes each. Obviously you can't just convert one to the other even if all values are in the range 0..255.
But back to the roots: if you need a slice of Cards, why do you create a slice of strings in the first place? You created the type Card because it is not a string (or at least not just a string). If so and you require []Card, then create []Card in the first place and all your problems go away:
value := []Card{"a", "b", "c"}
firstHand := NewHand(value)
fmt.Println(firstHand)
Note that you are still able to initialize the slice of Card with untyped constant string literals because it can be used to initialize any type whose underlying type is string. If you want to involve typed string constants or non-constant expressions of type string, you need explicit conversion, like in the example below:
s := "ddd"
value := []Card{"a", "b", "c", Card(s)}
If you have a []string, you need to manually build a []Card from it. There is no "easier" way. You can create a helper toCards() function so you can use it everywhere you need it.
func toCards(s []string) []Card {
c := make([]Card, len(s))
for i, v := range s {
c[i] = Card(v)
}
return c
}
Some links for background and reasoning:
Go Language Specification: Conversions
why []string can not be converted to []interface{} in golang
Cannot convert []string to []interface {}
What about memory layout means that []T cannot be converted to []interface in Go?
From the specs, it looks like []string is not the same underlying type as []Card, so the type conversion cannot occur.
Exactly right. You have to convert it by looping and copying over each element, converting the type from string to Card on the way.
If it is the case, why is it so? Assuming, in a non-pet-example program, I have as input a slice of string, is there any way to "cast" it into a slice of Card, or do I have to create a new structure and copy the data into it? (Which I'd like to avoid since the functions I'll need to call will modify the slice content).
Because conversions are always explicit and the designers felt that when a conversion implicitly involves a copy it should be made explicit as well.

Resources