blob: 71078aaedf847108b9ef7629300059bb2f161aff [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package signature
import "sort"
// SortableMethods implements sort.Interface, ordering by method name.
type SortableMethods []Method
func (s SortableMethods) Len() int { return len(s) }
func (s SortableMethods) Less(i, j int) bool { return s[i].Name < s[j].Name }
func (s SortableMethods) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// FindMethod returns the signature of the method with the given name and true
// iff the method exists, otherwise returns an empty signature and false.
func (s *Interface) FindMethod(name string) (Method, bool) {
// Use linear rather than binary search, in case the methods aren't sorted.
for _, method := range s.Methods {
if method.Name == name {
return method, true
}
}
return Method{}, false
}
// FirstMethod returns the signature of the method with the given name and true
// iff the method exists, otherwise returns an empty signature and false. If
// the method exists in more than one interface, we return the method from the
// the first interface with the given method name.
func FirstMethod(sig []Interface, name string) (Method, bool) {
for _, s := range sig {
if msig, ok := s.FindMethod(name); ok {
return msig, true
}
}
return Method{}, false
}
// CopyInterfaces returns a deep copy of x.
func CopyInterfaces(x []Interface) []Interface {
if len(x) == 0 {
return nil
}
ret := make([]Interface, len(x))
for i, iface := range x {
ret[i] = CopyInterface(iface)
}
return ret
}
// CopyInterface returns a deep copy of x.
func CopyInterface(x Interface) Interface {
x.Embeds = CopyEmbeds(x.Embeds)
x.Methods = CopyMethods(x.Methods)
return x
}
// CopyEmbeds returns a deep copy of x.
func CopyEmbeds(x []Embed) []Embed {
if len(x) == 0 {
return nil
}
ret := make([]Embed, len(x))
copy(ret, x)
return ret
}
// CopyMethods returns a deep copy of x.
func CopyMethods(x []Method) []Method {
if len(x) == 0 {
return nil
}
ret := make([]Method, len(x))
for i, method := range x {
ret[i] = CopyMethod(method)
}
return ret
}
// CopyMethod returns a deep copy of x.
func CopyMethod(x Method) Method {
x.InArgs = CopyArgs(x.InArgs)
x.OutArgs = CopyArgs(x.OutArgs)
x.InStream = copyArg(x.InStream)
x.OutStream = copyArg(x.OutStream)
return x
}
// CopyArgs returns a deep copy of x.
func CopyArgs(x []Arg) []Arg {
if len(x) == 0 {
return nil
}
ret := make([]Arg, len(x))
copy(ret, x)
return ret
}
// copyArg returns a deep copy of x.
func copyArg(x *Arg) *Arg {
if x == nil {
return nil
}
cp := *x
return &cp
}
// MethodNames returns a sorted list of all method names from x.
func MethodNames(sig []Interface) []string {
uniq := make(map[string]bool)
for _, iface := range sig {
for _, method := range iface.Methods {
uniq[method.Name] = true
}
}
var ret []string
for name, _ := range uniq {
ret = append(ret, name)
}
sort.Strings(ret)
return ret
}
// CleanInterfaces returns a cleaned version of sig. Duplicate interfaces are
// merged, duplicate embeds and methods are dropped, and all methods are sorted
// by name.
func CleanInterfaces(sig []Interface) []Interface {
// First merge duplicate interfaces.
ifaces := make(map[string]*Interface)
for _, iface := range sig {
key := interfaceKey(iface)
if exist := ifaces[key]; exist != nil {
mergeInterface(exist, iface)
} else {
n := new(Interface)
*n = CopyInterface(iface)
ifaces[key] = n
}
}
// Now drop duplicate embeds and methods.
for _, iface := range ifaces {
iface.Embeds = dedupEmbeds(iface.Embeds)
iface.Methods = dedupMethods(iface.Methods)
}
// Return interfaces, in the same relative order they were originally given.
var ret []Interface
for _, iface := range sig {
key := interfaceKey(iface)
if exist := ifaces[key]; exist != nil {
ret = append(ret, *exist)
delete(ifaces, key)
}
}
return ret
}
func interfaceKey(x Interface) string {
return x.PkgPath + "." + x.Name
}
func mergeInterface(dst *Interface, src Interface) {
if dst.Doc == "" {
dst.Doc = src.Doc
}
dst.Embeds = append(dst.Embeds, src.Embeds...)
dst.Methods = append(dst.Methods, src.Methods...)
}
func dedupEmbeds(x []Embed) []Embed {
seen := make(map[string]bool)
cur, end := 0, len(x)
for cur < end {
if key := x[cur].PkgPath + "." + x[cur].Name; seen[key] {
x[cur], x[end-1] = x[end-1], x[cur]
end--
} else {
seen[key] = true
cur++
}
}
return x[:end]
}
func dedupMethods(x []Method) []Method {
seen := make(map[string]bool)
cur, end := 0, len(x)
for cur < end {
if key := x[cur].Name; seen[key] {
x[cur], x[end-1] = x[end-1], x[cur]
end--
} else {
seen[key] = true
cur++
}
}
ret := x[:end]
sort.Sort(SortableMethods(ret))
return ret
}