diff --git a/example_extend_test.go b/example_extend_test.go new file mode 100644 index 0000000..ee87e3e --- /dev/null +++ b/example_extend_test.go @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: 2025 Comcast Cable Communications Management, LLC +// SPDX-License-Identifier: Apache-2.0 + +package wrp_test + +import ( + "fmt" + "strings" + + "github.com/xmidt-org/wrp-go/v5" +) + +type Extended struct { + wrp.SimpleEvent + Extra string +} + +var _ wrp.Union = (*Extended)(nil) + +// Implement the wrp.Union interface for the Extended type. +func (e *Extended) MsgType() wrp.MessageType { + return wrp.SimpleEventMessageType +} + +// Implement the wrp.Union interface for the Extended type. +func (e *Extended) To(msg *wrp.Message, v ...wrp.Processor) error { + e.SimpleEvent.Headers = []string{"extra: " + e.Extra} + return e.SimpleEvent.To(msg, v...) +} + +// Implement the wrp.Union interface for the Extended type. +func (e *Extended) From(msg *wrp.Message, v ...wrp.Processor) error { + err := e.SimpleEvent.From(msg, v...) + if err != nil { + return err + } + + e.Extra = "" + if len(e.SimpleEvent.Headers) > 0 { + after, found := strings.CutPrefix(e.SimpleEvent.Headers[0], "extra: ") + if found { + e.Extra = after + } + } + + return nil +} + +// Implement the wrp.Union interface for the Extended type. +func (e *Extended) Validate(v ...wrp.Processor) error { + return e.SimpleEvent.Validate(v...) +} + +// Is reports whether the msg is the same type as the target, or is convertible +// to the target, without the need to validate the message. This function is not +// part of the wrp.Union interface, but it is a useful function to have when working +// with the wrp.Union interface. +func (e *Extended) Is(msg wrp.Union) bool { + var tmp wrp.SimpleEvent + if wrp.As(msg, &tmp, wrp.NoStandardValidation()) == nil { + if len(tmp.Headers) > 0 && strings.HasPrefix(tmp.Headers[0], "extra: ") { + return true + } + } + + return false +} + +func Example_extend() { + isExtended := wrp.SimpleEvent{ + Headers: []string{"extra: something"}, + } + isNotExtended := wrp.SimpleEvent{} + + // The Extended type is a wrp.Union, so it can be used in the wrp.Is function. + // The wrp.Is function is useful for determining if the type matches, even if + // the message doesn't validate. + fmt.Printf("isExtended: %t\n", wrp.Is(&isExtended, &Extended{})) + fmt.Printf("isNotExtended: %t\n", wrp.Is(&isNotExtended, &Extended{})) + + // Output: isExtended: true + // isNotExtended: false +} diff --git a/is.go b/is.go index f0a9a6c..26b494d 100644 --- a/is.go +++ b/is.go @@ -9,6 +9,14 @@ package wrp // If the validators are not provided, the msg will be validated against the // default validators. To skip validation, provide the NoStandardValidation() // as a validator. +// +// If the target implements the Is(Union) bool method, that method will be +// called to determine if the msg is the same type as the target. If the target +// does not implement the Is(Union) method, the msg will be converted into a +// *Message and validated against the validators. +// +// Is() is valuable for determining if the type matches, even if the message +// doesn't validate. func Is(msg, target Union, validators ...Processor) bool { if msg == nil || target == nil { return msg == nil && target == nil @@ -21,6 +29,10 @@ func Is(msg, target Union, validators ...Processor) bool { return false } + if t, ok := target.(interface{ Is(Union) bool }); ok { + return t.Is(msg) + } + if m, ok := msg.(*Message); ok { if err := m.Validate(validators...); err != nil { return false diff --git a/is_test.go b/is_test.go index e1d7bf1..3e15c28 100644 --- a/is_test.go +++ b/is_test.go @@ -10,6 +10,38 @@ import ( "github.com/xmidt-org/wrp-go/v5" ) +// This type is here to show that a type that implements the wrp.Union interface +// can be used in the wrp.Is function. The Is() function is beyond the scope of +// of the wrp.Union interface, but it is a useful function to have when working +// with the wrp.Union interface as it allows the caller to determine if the +// message is of a specific type - even if it doesn't validate.. +type isTest struct { + is bool +} + +var _ wrp.Union = (*isTest)(nil) + +func (i *isTest) MsgType() wrp.MessageType { + return wrp.UnknownMessageType +} + +func (i *isTest) To(msg *wrp.Message, v ...wrp.Processor) error { + msg.Type = wrp.UnknownMessageType + return nil +} + +func (i *isTest) From(msg *wrp.Message, v ...wrp.Processor) error { + return nil +} + +func (i *isTest) Validate(v ...wrp.Processor) error { + return nil +} + +func (i *isTest) Is(msg wrp.Union) bool { + return i.is +} + func TestIs(t *testing.T) { tests := []struct { desc string @@ -68,6 +100,11 @@ func TestIs(t *testing.T) { msg: &wrp.Unknown{}, target: &wrp.Message{Type: wrp.UnknownMessageType}, want: true, + }, { + desc: "msg type matches exact type", + msg: &wrp.Message{Type: wrp.UnknownMessageType}, + target: &isTest{is: true}, + want: true, }, { desc: "msg type is not the same type", msg: &wrp.Message{Type: wrp.UnknownMessageType},