Skip to content

Add "clearomitted" directive#373

Merged
klauspost merged 2 commits intotinylib:masterfrom
klauspost:add-clearomitted-directive
Oct 22, 2024
Merged

Add "clearomitted" directive#373
klauspost merged 2 commits intotinylib:masterfrom
klauspost:add-clearomitted-directive

Conversation

@klauspost
Copy link
Collaborator

@klauspost klauspost commented Oct 21, 2024

Adds //msgp:clearomitted directive.

This will cause all omitempty and omitzero fields to be set to the zero value on Unmarshal and Decode, and the field wasn't present in the marshalled data.

This can be useful when de-serializing into reused objects, that can have values set for these, and we want to avoid clearing all fields, but also don't want existing fields to leak through.

Fields are tracked through a bit mask, and zeroed after the unmarshal loop, if no value has been written.

This does not affect marshaling.

DecodeMsg Example
// DecodeMsg implements msgp.Decodable
func (z *NamedStructCO) DecodeMsg(dc *msgp.Reader) (err error) {
	var field []byte
	_ = field
	var zb0001 uint32
	zb0001, err = dc.ReadMapHeader()
	if err != nil {
		err = msgp.WrapError(err)
		return
	}
	var zb0001Mask uint8 /* 2 bits */
	_ = zb0001Mask
	for zb0001 > 0 {
		zb0001--
		field, err = dc.ReadMapKeyPtr()
		if err != nil {
			err = msgp.WrapError(err)
			return
		}
		switch msgp.UnsafeString(field) {
		case "a":
			z.A, err = dc.ReadString()
			if err != nil {
				err = msgp.WrapError(err, "A")
				return
			}
			zb0001Mask |= 0x1
		case "b":
			z.B, err = dc.ReadString()
			if err != nil {
				err = msgp.WrapError(err, "B")
				return
			}
			zb0001Mask |= 0x2
		default:
			err = dc.Skip()
			if err != nil {
				err = msgp.WrapError(err)
				return
			}
		}
	}
	// Clear omitted fields.
	if zb0001Mask != 0x3 {
		if (zb0001Mask & 0x1) == 0 {
			z.A = ""
		}
		if (zb0001Mask & 0x2) == 0 {
			z.B = ""
		}
	}
	return
}
UnmarshalMsg Example
// UnmarshalMsg implements msgp.Unmarshaler
func (z *NamedStructCO) UnmarshalMsg(bts []byte) (o []byte, err error) {
	var field []byte
	_ = field
	var zb0001 uint32
	zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
	if err != nil {
		err = msgp.WrapError(err)
		return
	}
	var zb0001Mask uint8 /* 2 bits */
	_ = zb0001Mask
	for zb0001 > 0 {
		zb0001--
		field, bts, err = msgp.ReadMapKeyZC(bts)
		if err != nil {
			err = msgp.WrapError(err)
			return
		}
		switch msgp.UnsafeString(field) {
		case "a":
			z.A, bts, err = msgp.ReadStringBytes(bts)
			if err != nil {
				err = msgp.WrapError(err, "A")
				return
			}
			zb0001Mask |= 0x1
		case "b":
			z.B, bts, err = msgp.ReadStringBytes(bts)
			if err != nil {
				err = msgp.WrapError(err, "B")
				return
			}
			zb0001Mask |= 0x2
		default:
			bts, err = msgp.Skip(bts)
			if err != nil {
				err = msgp.WrapError(err)
				return
			}
		}
	}
	// Clear omitted fields.
	if zb0001Mask != 0x3 {
		if (zb0001Mask & 0x1) == 0 {
			z.A = ""
		}
		if (zb0001Mask & 0x2) == 0 {
			z.B = ""
		}
	}
	o = bts
	return
}

Adds `//msgp:clearomitted` directive.

This will cause all `omitempty` and `omitzero` fields to be set to the zero value on Unmarshal and Decode, and the field wasn't present in the marshalled data.

This can be useful when de-serializing into reused objects, that can have values set for these, and we want to avoid clearing all fields, but also don't want existing fields to leak through.

Fields are tracked through a bit mask, and zeroed after the unmarshal loop, if no value has been written.

This does not affect marshaling.
@klauspost klauspost requested a review from philhofer October 21, 2024 12:29
@klauspost
Copy link
Collaborator Author

Merging, but not publishing a release.

@klauspost klauspost merged commit 6da1c88 into tinylib:master Oct 22, 2024
@klauspost klauspost deleted the add-clearomitted-directive branch October 22, 2024 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants