Skip to content

Instantly share code, notes, and snippets.

@ianloic
Created January 8, 2021 23:19
Show Gist options
  • Save ianloic/142138a2dc318de8ec1b3705666b0aab to your computer and use it in GitHub Desktop.
Save ianloic/142138a2dc318de8ec1b3705666b0aab to your computer and use it in GitHub Desktop.
type piece interface {
Write(wr io.Writer)
}
type stringPiece string
func (sp stringPiece) Write(wr io.Writer) {
fmt.Fprint(wr, string(sp))
}
type Argument struct {
Type string
Name string
}
type Func struct {
virtual bool
explicit bool
Return string
Name string
args []Argument
override bool
body *Scope
equals string
}
func (f *Func) Write(wr io.Writer) {
var args []string = nil
for _, arg := range f.args {
args = append(args, fmt.Sprintf("%s %s", arg.Type, arg.Name))
}
if f.explicit {
fmt.Fprint(wr, "explicit ")
}
if f.virtual {
fmt.Fprint(wr, "virtual ")
}
fmt.Fprintf(wr, "%s %s(%s)", f.Return, f.Name, strings.Join(args, ", "))
if f.override {
fmt.Fprint(wr, " override")
}
if f.body == nil {
if f.equals != "" {
fmt.Fprintf(wr, " = %s", f.equals)
}
fmt.Fprintln(wr, ";")
} else {
fmt.Fprintln(wr, " {")
f.body.Write(wr)
fmt.Fprintln(wr, "}")
}
}
func (f *Func) Type() string {
var args []string = nil
for _, arg := range f.args {
args = append(args, arg.Type)
}
return fmt.Sprintf("%s(%s)", f.Return, strings.Join(args, ", "))
}
func (f *Func) Argument(t string, n string) *Func {
f.args = append(f.args, Argument{t, n})
return f
}
func (f *Func) Arguments(args []Argument) *Func {
f.args = append(f.args, args...)
return f
}
func (f *Func) Virtual() *Func {
f.virtual = true
return f
}
func (f *Func) Explicit() *Func {
f.explicit = true
return f
}
func (f *Func) Override() *Func {
f.override = true
return f
}
func (f *Func) PureVirtual() {
f.Virtual().equals = "0"
}
func (f *Func) Default() {
f.equals = "default"
}
func (f *Func) Delete() {
f.equals = "delete"
}
func (f *Func) Body(b func(s *Scope)) {
f.body = &Scope{}
b(f.body)
}
type Class struct {
Name string
final bool
extends []string
body *Scope
}
func (c *Class) Write(wr io.Writer) {
fmt.Fprintf(wr, "class %s", c.Name)
if c.final {
fmt.Fprint(wr, " final")
}
if c.extends != nil {
fmt.Fprintf(wr, " : %s", strings.Join(c.extends, ", "))
}
if c.body != nil {
fmt.Fprintln(wr, " {")
c.body.Write(wr)
fmt.Fprint(wr, "}")
}
fmt.Fprintln(wr, ";")
}
func (c *Class) Final() *Class {
c.final = true
return c
}
func (c *Class) Extend(visibility string, class string) *Class {
c.extends = append(c.extends, fmt.Sprint(visibility, class))
return c
}
func (c *Class) visibility(v string, f func(cs *ClassScope)) *Class {
if c.body == nil {
c.body = &Scope{}
}
cs := &ClassScope{&Scope{}, c}
c.body.add(cs)
cs.printf("%s:\n", v)
f(cs)
return c
}
// Public defines public members in a class
func (c *Class) Public(f func(cs *ClassScope)) *Class {
return c.visibility("public", f)
}
// Private defines public members in a class
func (c *Class) Private(f func(cs *ClassScope)) *Class {
return c.visibility("private", f)
}
type ClassScope struct {
*Scope
class *Class
}
func (cs *ClassScope) Ctor() *Func {
return cs.Func("", cs.class.Name)
}
func (cs *ClassScope) CopyCtor() *Func {
return cs.Ctor().Argument("const "+cs.class.Name+"&", "other")
}
func (cs *ClassScope) Dtor() *Func {
return cs.Func("", "~"+cs.class.Name)
}
func (cs *ClassScope) CopyOperator() *Func {
return cs.Func(cs.class.Name+"&", "operator=").Argument("const "+cs.class.Name+"&", "other")
}
func (cs *ClassScope) Friend(f string) {
cs.printf("friend %s;\n", f)
}
type Var struct {
typ string
name string
value string
}
func (v *Var) Write(wr io.Writer) {
fmt.Fprintf(wr, "%s %s", v.typ, v.name)
if v.value != "" {
fmt.Fprint(wr, " = %s", v.value)
}
fmt.Fprintln(wr, ";")
}
func (v *Var) Value(value string) {
v.value = value
}
type Scope struct {
pieces []piece
}
func (s *Scope) Write(wr io.Writer) {
for _, p := range s.pieces {
p.Write(wr)
}
}
func (s *Scope) add(piece piece) {
s.pieces = append(s.pieces, piece)
}
func (s *Scope) printf(format string, a ...interface{}) {
s.add(stringPiece(fmt.Sprintf(format, a...)))
}
func (s *Scope) println(line string) {
s.add(stringPiece(fmt.Sprintln(line)))
}
func (s *Scope) DocComments(a fidl.Attributes) {
for _, c := range a.DocComments() {
s.printf("///%s\n", c)
}
}
func (s *Scope) Using(new string, old string) {
s.printf("using %s = %s;\n", new, old)
}
func (s *Scope) Typedef(old string, new string) {
s.printf("typedef %s %s;\n", old, new)
}
func (s *Scope) Class(name string) *Class {
c := &Class{Name: name}
s.add(c)
return c
}
func (s *Scope) Var(t string, name string) *Var {
v := &Var{typ: t, name: name}
s.add(v)
return v
}
func (s *Scope) VarDecl(t string, name string) {
s.printf("%s %s;\n", t, name)
}
func (s *Scope) Func(ret string, name string) *Func {
f := &Func{Return: ret, Name: name}
s.add(f)
return f
}
func (s *Scope) IfdefFuchsia(f func(*Scope)) {
s.println("#ifdef __Fuchsia__")
f(s)
s.println("#endif // __Fuchsia__\n")
}
func (s *Scope) Namespace(name string, f func(*Scope)) {
s.printf("namespace %s {\n", name)
f(s)
s.printf("} // namespace %s\n\n", name)
}
func protocolForwardDeclaration(s *Scope, protocol *cpp.Protocol) {
s.IfdefFuchsia(func(s *Scope) {
s.DocComments(protocol.Attributes)
s.Using(fmt.Sprintf("%sPtr", protocol.Name),
fmt.Sprintf("::fidl::InterfacePtr<%s>", protocol.Name))
s.Class(protocol.ProxyName)
s.Class(protocol.StubName)
s.Class(protocol.EventSenderName)
s.Class(protocol.SyncName)
s.Using(fmt.Sprintf("%sSyncPtr", protocol.Name),
fmt.Sprintf("::fidl::SynchronousInterfacePtr<%s>", protocol.Name))
s.Class(protocol.SyncProxyName)
s.Namespace("internal", func(s *Scope) {
for _, method := range protocol.Methods {
s.Var("constexpr uint64_t", method.OrdinalName).Value(fmt.Sprintf("0x%Xlu", method.Ordinal))
}
})
})
}
func paramTypes(params []cpp.Parameter) string {
var types []string
for _, param := range params {
types = append(types, param.Type.FullDecl)
}
return strings.Join(types, ", ")
}
func argsFromParams(params []cpp.Parameter) []Argument {
var args []Argument
for _, param := range params {
args = append(args, Argument{
Name: param.Name,
Type: param.Type.FullDecl,
})
}
return args
}
// This should be defined on cpp.Method
func requestMethodFunc(s *ClassScope, m *cpp.Method) *Func {
f := s.Func("void", m.Name).Virtual().Arguments(argsFromParams(m.Request))
if m.HasResponse {
f.Argument(m.CallbackType, "callback")
}
return f
}
// This should be defined on cpp.Method
func responseMethodFunc(s *ClassScope, m *cpp.Method) *Func {
return s.Func("void", m.Name).Virtual().Arguments(argsFromParams(m.Request))
}
// This should be defined on cpp.Method
func syncMethodFunc(s *ClassScope, m *cpp.Method) *Func {
f := s.Func("zx_status_t", m.Name).Virtual().Arguments(argsFromParams(m.Request))
if m.HasResponse {
for _, arg := range m.Response {
f.Argument(arg.Type.FullDecl+"*", "out_"+arg.Name)
}
}
return f
}
func protocolDeclaration(s *Scope, protocol *cpp.Protocol) {
s.IfdefFuchsia(func(s *Scope) {
// Interface class
s.DocComments(protocol.Attributes)
s.Class(protocol.Name).
Public(func(s *ClassScope) {
s.Using("Proxy_", protocol.ProxyName)
s.Using("Stub_", protocol.StubName)
s.Using("EventSender_", protocol.EventSenderName)
s.Using("Sync_", protocol.SyncName)
if protocol.ServiceName != "" {
s.Var("static const char", "Name_[]")
}
s.Dtor().Virtual()
for _, method := range protocol.Methods {
if method.HasResponse {
s.Using(method.CallbackType,
fmt.Sprintf("%s<void(%s)>", method.CallbackWrapper(), paramTypes(method.Response)))
}
if method.HasRequest {
s.DocComments(method.Attributes)
f := requestMethodFunc(s, &method)
if method.Transitional {
f.Body(func(s *Scope) {})
} else {
f.PureVirtual()
}
}
}
})
// Request decoder class
s.Class(protocol.RequestDecoderName).
Public(func(s *ClassScope) {
s.Ctor().Default()
s.Dtor().Virtual().Default()
s.Func("static const fidl_type_t*", "GetType").
Argument("uint64_t", "ordinal").
Argument("bool*", "out_needs_response")
for _, method := range protocol.Methods {
if method.HasRequest {
requestMethodFunc(s, &method)
}
}
})
// Response decoder class
s.Class(protocol.ResponseDecoderName).Public(func(s *ClassScope) {
s.Ctor().Default()
s.Dtor().Virtual().Default()
s.Func("static const fidl_type_t*", "GetType").Argument("uint64_t", "ordinal")
for _, method := range protocol.Methods {
if method.HasResponse {
responseMethodFunc(s, &method)
}
}
})
// Event sender class
s.Class(protocol.EventSenderName).Public(func(s *ClassScope) {
s.Ctor()
for _, method := range protocol.Methods {
if !method.HasRequest && method.HasResponse {
responseMethodFunc(s, &method).PureVirtual()
}
}
})
// Sync interface class
s.Class(protocol.SyncName).Public(func(s *ClassScope) {
s.Using("Proxy_", protocol.SyncProxyName)
s.Dtor().Virtual()
for _, method := range protocol.Methods {
if method.HasRequest {
syncMethodFunc(s, &method).PureVirtual()
}
}
})
// Proxy class
s.Class(protocol.ProxyName).Final().
Extend("public", "::fidl::internal::Proxy").
Extend("public", protocol.Name).
Public(func(s *ClassScope) {
s.Ctor().Explicit().Argument("::fidl::internal::ProxyController*", "controller")
s.Dtor().Override()
s.Func("zx_status_t", "Dispatch_").
Argument("::fidl::HLCPPIncomingMessage", "message").
Override()
for _, method := range protocol.Methods {
if method.HasRequest {
requestMethodFunc(s, &method).Override()
} else {
if method.HasResponse {
s.Var(method.CallbackType, method.Name)
}
}
}
}).
Private(func(s *ClassScope) {
s.CopyCtor().Delete()
s.CopyOperator().Delete()
})
// Stub class
s.Class(protocol.StubName).Final().
Extend("public", "::fidl::internal::Stub").
Extend("public", protocol.EventSenderName).
Public(func(s *ClassScope) {
s.Typedef(fmt.Sprintf("class %s::%s", protocol.Namespace, protocol.Name), protocol.ClassName)
s.Ctor().Explicit().Argument(protocol.ClassName+"*", "impl")
s.Dtor().Override()
s.Func("zx_status_t", "Dispatch_").
Argument("::fidl::HLCPPIncomingMessage", "message").
Argument("::fidl::internal::PendingResponse", "response").
Override()
for _, method := range protocol.Methods {
if !method.HasRequest && method.HasResponse {
responseMethodFunc(s, &method).Override()
}
}
}).
Private(func(s *ClassScope) {
s.Var(protocol.ClassName+"*", "impl_")
})
// Sync proxy class
s.Class(protocol.SyncProxyName).
Extend("public", protocol.SyncName).
Public(func(s *ClassScope) {
s.Ctor().Explicit().Argument("::zx::channel", "channel")
s.Dtor().Override()
for _, method := range protocol.Methods {
if method.HasRequest {
syncMethodFunc(s, &method).Override()
}
}
}).
Private(func(s *ClassScope) {
s.Var("::fidl::internal::SynchronousProxy", "proxy_")
s.Friend("class ::fidl::SynchronousInterfacePtr<" + protocol.Name + ">")
})
})
}
const protocolTemplateProxiesAndStubs = `
{{- define "ProtocolForwardDeclaration/ProxiesAndStubs" }}
#ifdef __Fuchsia__
{{- range .DocComments }}
///{{ . }}
{{- end }}
using {{ .Name }}Ptr = ::fidl::InterfacePtr<{{ .Name }}>;
class {{ .ProxyName }};
class {{ .StubName }};
class {{ .EventSenderName }};
class {{ .SyncName }};
using {{ .Name }}SyncPtr = ::fidl::SynchronousInterfacePtr<{{ .Name }}>;
class {{ .SyncProxyName }};
namespace internal {
{{- range .Methods }}
constexpr uint64_t {{ .OrdinalName }} = {{ .Ordinal | printf "%#x" }}lu;
{{- end }}
} // namespace
#endif // __Fuchsia__
{{- end }}
{{- define "Params" -}}
{{- range $index, $param := . -}}
{{- if $index }}, {{ end -}}{{ $param.Type.FullDecl }} {{ $param.Name }}
{{- end -}}
{{ end }}
{{- define "OutParams" -}}
{{- range $index, $param := . -}}
{{- if $index }}, {{ end -}}{{ $param.Type.FullDecl }}* out_{{ $param.Name }}
{{- end -}}
{{ end }}
{{- define "ParamTypes" -}}
{{- range $index, $param := . -}}
{{- if $index }}, {{ end -}}{{ $param.Type.FullDecl }}
{{- end -}}
{{ end }}
{{- define "RequestMethodSignature" -}}
{{- if .HasResponse -}}
{{ .Name }}({{ template "Params" .Request }}{{ if .Request }}, {{ end }}{{ .CallbackType }} callback)
{{- else -}}
{{ .Name }}({{ template "Params" .Request }})
{{- end -}}
{{ end -}}
{{- define "EventMethodSignature" -}}
{{ .Name }}({{ template "Params" .Response }})
{{- end -}}
{{- define "SyncRequestMethodSignature" -}}
{{- if .Response -}}
{{ .Name }}({{ template "Params" .Request }}{{ if .Request }}, {{ end }}{{ template "OutParams" .Response }})
{{- else -}}
{{ .Name }}({{ template "Params" .Request }})
{{- end -}}
{{ end -}}
{{- define "ProtocolDeclaration/ProxiesAndStubs" }}
#ifdef __Fuchsia__
{{- range .DocComments }}
///{{ . }}
{{- end }}
class {{ .Name }} {
public:
using Proxy_ = {{ .ProxyName }};
using Stub_ = {{ .StubName }};
using EventSender_ = {{ .EventSenderName }};
using Sync_ = {{ .SyncName }};
{{- if .ServiceName }}
static const char Name_[];
{{- end }}
virtual ~{{ .Name }}();
{{- range .Methods }}
{{- if .HasResponse }}
using {{ .CallbackType }} =
{{ .CallbackWrapper }}<void({{ template "ParamTypes" .Response }})>;
{{- end }}
{{- if .HasRequest }}
{{ range .DocComments }}
///{{ . }}
{{- end }}
{{- if .Transitional }}
virtual void {{ template "RequestMethodSignature" . }} { }
{{- else }}
virtual void {{ template "RequestMethodSignature" . }} = 0;
{{- end }}
{{- end }}
{{- end }}
};
class {{ .RequestDecoderName }} {
public:
{{ .RequestDecoderName }}() = default;
virtual ~{{ .RequestDecoderName }}() = default;
static const fidl_type_t* GetType(uint64_t ordinal, bool* out_needs_response);
{{- range .Methods }}
{{- if .HasRequest }}
virtual void {{ .Name }}({{ template "Params" .Request }}) = 0;
{{- end }}
{{- end }}
};
class {{ .ResponseDecoderName }} {
public:
{{ .ResponseDecoderName }}() = default;
virtual ~{{ .ResponseDecoderName }}() = default;
static const fidl_type_t* GetType(uint64_t ordinal);
{{- range .Methods }}
{{- if .HasResponse }}
virtual void {{ .Name }}({{ template "Params" .Response }}) = 0;
{{- end }}
{{- end }}
};
class {{ .EventSenderName }} {
public:
virtual ~{{ .EventSenderName }}();
{{- range .Methods }}
{{- if not .HasRequest }}
{{- if .HasResponse }}
virtual void {{ template "EventMethodSignature" . }} = 0;
{{- end }}
{{- end }}
{{- end }}
};
class {{ .SyncName }} {
public:
using Proxy_ = {{ .SyncProxyName }};
virtual ~{{ .SyncName }}();
{{- range .Methods }}
{{- if .HasRequest }}
virtual zx_status_t {{ template "SyncRequestMethodSignature" . }} = 0;
{{- end }}
{{- end }}
};
class {{ .ProxyName }} final : public ::fidl::internal::Proxy, public {{ .Name }} {
public:
explicit {{ .ProxyName }}(::fidl::internal::ProxyController* controller);
~{{ .ProxyName }}() override;
zx_status_t Dispatch_(::fidl::HLCPPIncomingMessage message) override;
{{- range .Methods }}
{{- if .HasRequest }}
void {{ template "RequestMethodSignature" . }} override;
{{- else if .HasResponse }}
{{ .CallbackType }} {{ .Name }};
{{- end }}
{{- end }}
private:
{{ .ProxyName }}(const {{ .ProxyName }}&) = delete;
{{ .ProxyName }}& operator=(const {{ .ProxyName }}&) = delete;
::fidl::internal::ProxyController* controller_;
};
class {{ .StubName }} final : public ::fidl::internal::Stub, public {{ .EventSenderName }} {
public:
typedef class {{ .Namespace }}::{{ .Name }} {{ .ClassName }};
explicit {{ .StubName }}({{ .ClassName }}* impl);
~{{ .StubName }}() override;
zx_status_t Dispatch_(::fidl::HLCPPIncomingMessage message,
::fidl::internal::PendingResponse response) override;
{{- range .Methods }}
{{- if not .HasRequest }}
{{- if .HasResponse }}
void {{ template "EventMethodSignature" . }} override;
{{- end }}
{{- end }}
{{- end }}
private:
{{ .ClassName }}* impl_;
};
class {{ .SyncProxyName }} : public {{ .SyncName }} {
public:
explicit {{ .SyncProxyName }}(::zx::channel channel);
~{{ .SyncProxyName }}() override;
{{- range .Methods }}
{{- if .HasRequest }}
zx_status_t {{ template "SyncRequestMethodSignature" . }} override;
{{- end }}
{{- end }}
private:
::fidl::internal::SynchronousProxy proxy_;
friend class ::fidl::SynchronousInterfacePtr<{{ .Name }}>;
};
#endif // __Fuchsia__
{{- end }}
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment