From ccf92eb84d6b254da88f8bb9b1ad0b8493153f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=93=D0=BE=D1=80?= =?UTF-8?q?=D0=B1=D1=83=D0=BD=D0=BE=D0=B2?= Date: Tue, 27 Feb 2024 23:35:49 +0300 Subject: [PATCH] As for interface casting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gorbunov Kirill Andreevich Reviewed-on: https://git.unistack.org/unistack-org/micro/pulls/299 Co-authored-by: Кирилл Горбунов Co-committed-by: Кирилл Горбунов --- micro.go | 94 +++++++++++++++++++++++++++++++++++++++++ micro_test.go | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 micro.go create mode 100644 micro_test.go diff --git a/micro.go b/micro.go new file mode 100644 index 00000000..20295601 --- /dev/null +++ b/micro.go @@ -0,0 +1,94 @@ +package micro + +import ( + "reflect" + + "go.unistack.org/micro/v3/broker" + "go.unistack.org/micro/v3/client" + "go.unistack.org/micro/v3/codec" + "go.unistack.org/micro/v3/flow" + "go.unistack.org/micro/v3/fsm" + "go.unistack.org/micro/v3/logger" + "go.unistack.org/micro/v3/meter" + "go.unistack.org/micro/v3/register" + "go.unistack.org/micro/v3/resolver" + "go.unistack.org/micro/v3/router" + "go.unistack.org/micro/v3/selector" + "go.unistack.org/micro/v3/server" + "go.unistack.org/micro/v3/store" + "go.unistack.org/micro/v3/sync" + "go.unistack.org/micro/v3/tracer" +) + +func As(b any, target any) bool { + if b == nil { + return false + } + if target == nil { + return false + } + val := reflect.ValueOf(target) + typ := val.Type() + if typ.Kind() != reflect.Ptr || val.IsNil() { + return false + } + targetType := typ.Elem() + if targetType.Kind() != reflect.Interface { + switch { + case targetType.Implements(brokerType): + break + case targetType.Implements(loggerType): + break + case targetType.Implements(clientType): + break + case targetType.Implements(serverType): + break + case targetType.Implements(codecType): + break + case targetType.Implements(flowType): + break + case targetType.Implements(fsmType): + break + case targetType.Implements(meterType): + break + case targetType.Implements(registerType): + break + case targetType.Implements(resolverType): + break + case targetType.Implements(selectorType): + break + case targetType.Implements(storeType): + break + case targetType.Implements(syncType): + break + case targetType.Implements(serviceType): + break + case targetType.Implements(routerType): + break + default: + return false + } + } + if reflect.TypeOf(b).AssignableTo(targetType) { + val.Elem().Set(reflect.ValueOf(b)) + return true + } + return false +} + +var brokerType = reflect.TypeOf((*broker.Broker)(nil)).Elem() +var loggerType = reflect.TypeOf((*logger.Logger)(nil)).Elem() +var clientType = reflect.TypeOf((*client.Client)(nil)).Elem() +var serverType = reflect.TypeOf((*server.Server)(nil)).Elem() +var codecType = reflect.TypeOf((*codec.Codec)(nil)).Elem() +var flowType = reflect.TypeOf((*flow.Flow)(nil)).Elem() +var fsmType = reflect.TypeOf((*fsm.FSM)(nil)).Elem() +var meterType = reflect.TypeOf((*meter.Meter)(nil)).Elem() +var registerType = reflect.TypeOf((*register.Register)(nil)).Elem() +var resolverType = reflect.TypeOf((*resolver.Resolver)(nil)).Elem() +var routerType = reflect.TypeOf((*router.Router)(nil)).Elem() +var selectorType = reflect.TypeOf((*selector.Selector)(nil)).Elem() +var storeType = reflect.TypeOf((*store.Store)(nil)).Elem() +var syncType = reflect.TypeOf((*sync.Sync)(nil)).Elem() +var tracerType = reflect.TypeOf((*tracer.Tracer)(nil)).Elem() +var serviceType = reflect.TypeOf((*Service)(nil)).Elem() diff --git a/micro_test.go b/micro_test.go new file mode 100644 index 00000000..d2a20121 --- /dev/null +++ b/micro_test.go @@ -0,0 +1,115 @@ +package micro + +import ( + "context" + "fmt" + "reflect" + "testing" + + "go.unistack.org/micro/v3/broker" + "go.unistack.org/micro/v3/fsm" +) + +func TestAs(t *testing.T) { + var b *bro + broTarget := &bro{name: "kafka"} + fsmTarget := &fsmT{name: "fsm"} + + testCases := []struct { + b any + target any + match bool + want any + }{ + { + broTarget, + &b, + true, + broTarget, + }, + { + nil, + &b, + false, + nil, + }, + { + fsmTarget, + &b, + false, + nil, + }, + } + for i, tc := range testCases { + name := fmt.Sprintf("%d:As(Errorf(..., %v), %v)", i, tc.b, tc.target) + // Clear the target pointer, in case it was set in a previous test. + rtarget := reflect.ValueOf(tc.target) + rtarget.Elem().Set(reflect.Zero(reflect.TypeOf(tc.target).Elem())) + t.Run(name, func(t *testing.T) { + match := As(tc.b, tc.target) + if match != tc.match { + t.Fatalf("match: got %v; want %v", match, tc.match) + } + if !match { + return + } + if got := rtarget.Elem().Interface(); got != tc.want { + t.Fatalf("got %#v, want %#v", got, tc.want) + } + }) + } +} + +type bro struct { + name string +} + +func (p *bro) Name() string { return p.name } + +func (p *bro) Init(opts ...broker.Option) error { return nil } + +// Options returns broker options +func (p *bro) Options() broker.Options { return broker.Options{} } + +// Address return configured address +func (p *bro) Address() string { return "" } + +// Connect connects to broker +func (p *bro) Connect(ctx context.Context) error { return nil } + +// Disconnect disconnect from broker +func (p *bro) Disconnect(ctx context.Context) error { return nil } + +// Publish message, msg can be single broker.Message or []broker.Message +func (p *bro) Publish(ctx context.Context, topic string, msg *broker.Message, opts ...broker.PublishOption) error { + return nil +} + +// BatchPublish messages to broker with multiple topics +func (p *bro) BatchPublish(ctx context.Context, msgs []*broker.Message, opts ...broker.PublishOption) error { + return nil +} + +// BatchSubscribe subscribes to topic messages via handler +func (p *bro) BatchSubscribe(ctx context.Context, topic string, h broker.BatchHandler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { + return nil, nil +} + +// Subscribe subscribes to topic message via handler +func (p *bro) Subscribe(ctx context.Context, topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { + return nil, nil +} + +// String type of broker +func (p *bro) String() string { return p.name } + +type fsmT struct { + name string +} + +func (f *fsmT) Start(ctx context.Context, a interface{}, o ...Option) (interface{}, error) { + return nil, nil +} +func (f *fsmT) Current() string { return f.name } +func (f *fsmT) Reset() {} +func (f *fsmT) State(s string, sf fsm.StateFunc) {}