diff --git a/libevm/options/example_test.go b/libevm/options/example_test.go new file mode 100644 index 00000000000..a04242cee6a --- /dev/null +++ b/libevm/options/example_test.go @@ -0,0 +1,66 @@ +// Copyright 2025 the libevm authors. +// +// The libevm additions to go-ethereum are free software: you can redistribute +// them and/or modify them under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The libevm additions are distributed in the hope that they will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see +// . + +package options_test + +import ( + "fmt" + + "github.com/ava-labs/libevm/libevm/options" +) + +// config is an arbitrary type to be configured with [options.Option] values. +// Although it can be exported, there is typically no need. +type config struct { + num int + flag bool +} + +// An Option configures an arbitrary type. Using a type alias (=) instead of a +// completely new type is recommended as it maintains compatibility with helpers +// such as [options.Func]. +type Option = options.Option[config] + +func WithNum(n int) Option { + return options.Func[config](func(c *config) { + c.num = n + }) +} + +func WithFlag(b bool) Option { + return options.Func[config](func(c *config) { + c.flag = b + }) +} + +func Example() { + num42 := WithNum(42) + flagOn := WithFlag(true) + + // Some IDEs and linters might complain about the redundant type parameter + // as it can be inferred, but it makes for more readable code. + fromZero := options.As[config](num42, flagOn) + fmt.Printf("From zero value: %T(%+[1]v)\n", fromZero) + + fromDefault := options.ApplyTo(&config{ + num: 100, + }, flagOn) + fmt.Printf("Applied to default value: %T(%+[1]v)\n", fromDefault) + + // Output: + // From zero value: *options_test.config(&{num:42 flag:true}) + // Applied to default value: *options_test.config(&{num:100 flag:true}) +} diff --git a/libevm/options/options.go b/libevm/options/options.go index af7bc751a96..97c9e5b6f3f 100644 --- a/libevm/options/options.go +++ b/libevm/options/options.go @@ -26,10 +26,15 @@ type Option[T any] interface { // As applies Options to a zero-value T, which it then returns. func As[T any](opts ...Option[T]) *T { var t T + return ApplyTo(&t, opts...) +} + +// ApplyTo applies Options to the T and returns it for convenience. +func ApplyTo[T any](t *T, opts ...Option[T]) *T { for _, o := range opts { - o.Configure(&t) + o.Configure(t) } - return &t + return t } // A Func converts a function into an [Option], using itself as the Configure