-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
112 additions
and
25 deletions.
There are no files selected for viewing
25 changes: 0 additions & 25 deletions
25
processor/deltatocumulativeprocessor/internal/maybe/option.go
This file was deleted.
Oops, something went wrong.
52 changes: 52 additions & 0 deletions
52
processor/deltatocumulativeprocessor/internal/maybe/ptr.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// maybe provides utilities for representing data may or may not exist at | ||
// runtime in a safe way. | ||
// | ||
// A typical approach to this are pointers, but they suffer from two issues: | ||
// - Unsafety: permitting nil pointers must require careful checking on each use, | ||
// which is easily forgotten | ||
// - Blindness: nil itself does cannot differentiate between "set to nil" and | ||
// "not set all", leading to unexepcted edge cases | ||
// | ||
// The [Ptr] type of this package provides a safe alternative with a clear | ||
// distinction between "not set" and "set to nil". | ||
package maybe // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor/internal/maybe" | ||
|
||
// Ptr references some value of type T that is not guaranteed to exist. | ||
// Callers must use [Ptr.Try] to access the underlying value, checking the | ||
// ok return value too. | ||
// This provides a clear distinction between "not set" and "set to nil". | ||
// | ||
// Use [Some] and [None] to create Ptrs. | ||
type Ptr[T any] struct { | ||
to *T | ||
ok bool | ||
} | ||
|
||
// None returns a Ptr that represents "not-set". | ||
// This is equal to a zero-value Ptr. | ||
func None[T any]() Ptr[T] { | ||
return Ptr[T]{to: nil, ok: false} | ||
} | ||
|
||
// Some returns a pointer to the passed T. | ||
// | ||
// The ptr argument may be nil, in which case this represents "explictely set to | ||
// nil". | ||
func Some[T any](ptr *T) Ptr[T] { | ||
return Ptr[T]{to: ptr, ok: true} | ||
} | ||
|
||
// Try attempts to de-reference the Ptr, giving one of three results: | ||
// | ||
// - nil, false: not-set | ||
// - nil, true: explicitely set to nil | ||
// - non-nil, true: set to some value | ||
// | ||
// This provides extra safety over bare pointers, because callers are forced by | ||
// the compiler to either check or explicitely ignore the ok value. | ||
func (ptr Ptr[T]) Try() (_ *T, ok bool) { | ||
return ptr.to, ptr.ok | ||
} |
60 changes: 60 additions & 0 deletions
60
processor/deltatocumulativeprocessor/internal/maybe/ptr_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package maybe_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor/internal/maybe" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestMaybe(t *testing.T) { | ||
t.Run("zero-not-ok", func(t *testing.T) { | ||
var ptr maybe.Ptr[int] | ||
_, ok := ptr.Try() | ||
require.False(t, ok) | ||
}) | ||
t.Run("none-not-ok", func(t *testing.T) { | ||
ptr := maybe.None[int]() | ||
_, ok := ptr.Try() | ||
require.False(t, ok) | ||
}) | ||
t.Run("explicit-nil", func(t *testing.T) { | ||
ptr := maybe.Some[int](nil) | ||
v, ok := ptr.Try() | ||
require.Nil(t, v) | ||
require.True(t, ok) | ||
}) | ||
t.Run("value", func(t *testing.T) { | ||
num := 42 | ||
ptr := maybe.Some(&num) | ||
v, ok := ptr.Try() | ||
require.True(t, ok) | ||
require.Equal(t, num, *v) | ||
}) | ||
} | ||
|
||
func ExamplePtr() { | ||
var unset maybe.Ptr[int] // = maybe.None() | ||
if v, ok := unset.Try(); ok { | ||
fmt.Println("unset:", v) | ||
} else { | ||
fmt.Println("unset: !ok") | ||
} | ||
|
||
var xnil maybe.Ptr[int] = maybe.Some[int](nil) | ||
if v, ok := xnil.Try(); ok { | ||
fmt.Println("explicit nil:", v) | ||
} | ||
|
||
num := 42 | ||
var set maybe.Ptr[int] = maybe.Some(&num) | ||
if v, ok := set.Try(); ok { | ||
fmt.Println("set:", *v) | ||
} | ||
|
||
// Output: | ||
// unset: !ok | ||
// explicit nil: <nil> | ||
// set: 42 | ||
} |