package main
import (
"context"
"fmt"
"github.com/ServiceWeaver/weaver"
)
type Adder interface {
Add(context.Context, int, int) (int, error)
}
type adder struct {
weaver.Implements[Adder]
}
func (a adder) Add(_ context.Context, x, y int) (int, error) {
return x + y, nil
}
type adder2 struct {
weaver.Implements[Adder]
}
func (a adder2) Add(_ context.Context, x, y int) (int, error) {
return x + 2*y, nil
}
func main() {
ctx := context.Background()
root := weaver.Init(ctx)
addrer, err := weaver.Get[Adder](root)
if err != nil {
panic(err)
}
sum, err := addrer.Add(ctx, 1, 2)
if err != nil {
panic(err)
}
fmt.Println(sum)
}
it will generate a duplicate adder_local_stub struct.
package main
// Code generated by "weaver generate". DO NOT EDIT.
import (
"context"
"github.com/ServiceWeaver/weaver/runtime/codegen"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"reflect"
"time"
)
func init() {
codegen.Register(codegen.Registration{
Name: "weaver-test/Adder",
Iface: reflect.TypeOf((*Adder)(nil)).Elem(),
New: func() any { return &adder{} },
LocalStubFn: func(impl any, tracer trace.Tracer) any { return adder_local_stub{impl: impl.(Adder), tracer: tracer} },
ClientStubFn: func(stub codegen.Stub, caller string) any {
return adder_client_stub{stub: stub, addMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "weaver-test/Adder", Method: "Add"})}
},
ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server {
return adder_server_stub{impl: impl.(Adder), addLoad: addLoad}
},
})
codegen.Register(codegen.Registration{
Name: "weaver-test/Adder",
Iface: reflect.TypeOf((*Adder)(nil)).Elem(),
New: func() any { return &adder2{} },
LocalStubFn: func(impl any, tracer trace.Tracer) any { return adder_local_stub{impl: impl.(Adder), tracer: tracer} },
ClientStubFn: func(stub codegen.Stub, caller string) any {
return adder_client_stub{stub: stub, addMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "weaver-test/Adder", Method: "Add"})}
},
ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server {
return adder_server_stub{impl: impl.(Adder), addLoad: addLoad}
},
})
}
// Local stub implementations.
type adder_local_stub struct {
impl Adder
tracer trace.Tracer
}
func (s adder_local_stub) Add(ctx context.Context, a0 int, a1 int) (r0 int, err error) {
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
// Create a child span for this method.
ctx, span = s.tracer.Start(ctx, "main.Adder.Add", trace.WithSpanKind(trace.SpanKindInternal))
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
span.End()
}()
}
return s.impl.Add(ctx, a0, a1)
}
type adder_local_stub struct {
impl Adder
tracer trace.Tracer
}
func (s adder_local_stub) Add(ctx context.Context, a0 int, a1 int) (r0 int, err error) {
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
// Create a child span for this method.
ctx, span = s.tracer.Start(ctx, "main.Adder.Add", trace.WithSpanKind(trace.SpanKindInternal))
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
span.End()
}()
}
return s.impl.Add(ctx, a0, a1)
}
// Client stub implementations.
type adder_client_stub struct {
stub codegen.Stub
addMetrics *codegen.MethodMetrics
}
func (s adder_client_stub) Add(ctx context.Context, a0 int, a1 int) (r0 int, err error) {
// Update metrics.
start := time.Now()
s.addMetrics.Count.Add(1)
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
// Create a child span for this method.
ctx, span = s.stub.Tracer().Start(ctx, "main.Adder.Add", trace.WithSpanKind(trace.SpanKindClient))
}
defer func() {
// Catch and return any panics detected during encoding/decoding/rpc.
if err == nil {
err = codegen.CatchPanics(recover())
}
err = s.stub.WrapError(err)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
s.addMetrics.ErrorCount.Add(1)
}
span.End()
s.addMetrics.Latency.Put(float64(time.Since(start).Microseconds()))
}()
// Preallocate a buffer of the right size.
size := 0
size += 8
size += 8
enc := codegen.NewEncoder()
enc.Reset(size)
// Encode arguments.
enc.Int(a0)
enc.Int(a1)
var shardKey uint64
// Call the remote method.
s.addMetrics.BytesRequest.Put(float64(len(enc.Data())))
var results []byte
results, err = s.stub.Run(ctx, 0, enc.Data(), shardKey)
if err != nil {
return
}
s.addMetrics.BytesReply.Put(float64(len(results)))
// Decode the results.
dec := codegen.NewDecoder(results)
r0 = dec.Int()
err = dec.Error()
return
}
type adder_client_stub struct {
stub codegen.Stub
addMetrics *codegen.MethodMetrics
}
func (s adder_client_stub) Add(ctx context.Context, a0 int, a1 int) (r0 int, err error) {
// Update metrics.
start := time.Now()
s.addMetrics.Count.Add(1)
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
// Create a child span for this method.
ctx, span = s.stub.Tracer().Start(ctx, "main.Adder.Add", trace.WithSpanKind(trace.SpanKindClient))
}
defer func() {
// Catch and return any panics detected during encoding/decoding/rpc.
if err == nil {
err = codegen.CatchPanics(recover())
}
err = s.stub.WrapError(err)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
s.addMetrics.ErrorCount.Add(1)
}
span.End()
s.addMetrics.Latency.Put(float64(time.Since(start).Microseconds()))
}()
// Preallocate a buffer of the right size.
size := 0
size += 8
size += 8
enc := codegen.NewEncoder()
enc.Reset(size)
// Encode arguments.
enc.Int(a0)
enc.Int(a1)
var shardKey uint64
// Call the remote method.
s.addMetrics.BytesRequest.Put(float64(len(enc.Data())))
var results []byte
results, err = s.stub.Run(ctx, 0, enc.Data(), shardKey)
if err != nil {
return
}
s.addMetrics.BytesReply.Put(float64(len(results)))
// Decode the results.
dec := codegen.NewDecoder(results)
r0 = dec.Int()
err = dec.Error()
return
}
// Server stub implementations.
type adder_server_stub struct {
impl Adder
addLoad func(key uint64, load float64)
}
// GetStubFn implements the stub.Server interface.
func (s adder_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) {
switch method {
case "Add":
return s.add
default:
return nil
}
}
func (s adder_server_stub) add(ctx context.Context, args []byte) (res []byte, err error) {
// Catch and return any panics detected during encoding/decoding/rpc.
defer func() {
if err == nil {
err = codegen.CatchPanics(recover())
}
}()
// Decode arguments.
dec := codegen.NewDecoder(args)
var a0 int
a0 = dec.Int()
var a1 int
a1 = dec.Int()
// TODO(rgrandl): The deferred function above will recover from panics in the
// user code: fix this.
// Call the local method.
r0, appErr := s.impl.Add(ctx, a0, a1)
// Encode the results.
enc := codegen.NewEncoder()
enc.Int(r0)
enc.Error(appErr)
return enc.Data(), nil
}
type adder_server_stub struct {
impl Adder
addLoad func(key uint64, load float64)
}
// GetStubFn implements the stub.Server interface.
func (s adder_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) {
switch method {
case "Add":
return s.add
default:
return nil
}
}
func (s adder_server_stub) add(ctx context.Context, args []byte) (res []byte, err error) {
// Catch and return any panics detected during encoding/decoding/rpc.
defer func() {
if err == nil {
err = codegen.CatchPanics(recover())
}
}()
// Decode arguments.
dec := codegen.NewDecoder(args)
var a0 int
a0 = dec.Int()
var a1 int
a1 = dec.Int()
// TODO(rgrandl): The deferred function above will recover from panics in the
// user code: fix this.
// Call the local method.
r0, appErr := s.impl.Add(ctx, a0, a1)
// Encode the results.
enc := codegen.NewEncoder()
enc.Int(r0)
enc.Error(appErr)
return enc.Data(), nil
}