github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/protobuf/plugin/deepcopy/deepcopy.go (about) 1 package deepcopy 2 3 import ( 4 "github.com/docker/swarmkit/protobuf/plugin" 5 "github.com/gogo/protobuf/gogoproto" 6 "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" 7 "github.com/gogo/protobuf/protoc-gen-gogo/generator" 8 ) 9 10 type deepCopyGen struct { 11 *generator.Generator 12 generator.PluginImports 13 copyPkg generator.Single 14 } 15 16 func init() { 17 generator.RegisterPlugin(new(deepCopyGen)) 18 } 19 20 func (d *deepCopyGen) Name() string { 21 return "deepcopy" 22 } 23 24 func (d *deepCopyGen) Init(g *generator.Generator) { 25 d.Generator = g 26 } 27 28 func (d *deepCopyGen) genCopyFunc(dst, src string) { 29 d.P(d.copyPkg.Use(), ".Copy(", dst, ", ", src, ")") 30 } 31 32 func (d *deepCopyGen) genCopyBytes(dst, src string) { 33 d.P("if ", src, " != nil {") 34 d.In() 35 // allocate dst object 36 d.P(dst, " = make([]byte, len(", src, "))") 37 // copy bytes from src to dst 38 d.P("copy(", dst, ", ", src, ")") 39 d.Out() 40 d.P("}") 41 } 42 43 func (d *deepCopyGen) genMsgDeepCopy(m *generator.Descriptor) { 44 ccTypeName := generator.CamelCaseSlice(m.TypeName()) 45 46 // Generate backwards compatible, type-safe Copy() function. 47 d.P("func (m *", ccTypeName, ") Copy() *", ccTypeName, "{") 48 d.In() 49 d.P("if m == nil {") 50 d.In() 51 d.P("return nil") 52 d.Out() 53 d.P("}") 54 d.P("o := &", ccTypeName, "{}") 55 d.P("o.CopyFrom(m)") 56 d.P("return o") 57 d.Out() 58 d.P("}") 59 d.P() 60 61 if len(m.Field) == 0 { 62 d.P("func (m *", ccTypeName, ") CopyFrom(src interface{})", " {}") 63 return 64 } 65 66 d.P("func (m *", ccTypeName, ") CopyFrom(src interface{})", " {") 67 d.P() 68 69 d.P("o := src.(*", ccTypeName, ")") 70 71 // shallow copy handles all scalars 72 d.P("*m = *o") 73 74 oneofByIndex := [][]*descriptor.FieldDescriptorProto{} 75 for _, f := range m.Field { 76 fName := generator.CamelCase(*f.Name) 77 if gogoproto.IsCustomName(f) { 78 fName = gogoproto.GetCustomName(f) 79 } 80 81 // Handle oneof type, we defer them to a loop below 82 if f.OneofIndex != nil { 83 if len(oneofByIndex) <= int(*f.OneofIndex) { 84 oneofByIndex = append(oneofByIndex, []*descriptor.FieldDescriptorProto{}) 85 } 86 87 oneofByIndex[*f.OneofIndex] = append(oneofByIndex[*f.OneofIndex], f) 88 continue 89 } 90 91 // Handle all kinds of message type 92 if f.IsMessage() { 93 // Handle map type 94 if d.genMap(m, f) { 95 continue 96 } 97 98 // Handle any message which is not repeated or part of oneof 99 if !f.IsRepeated() && f.OneofIndex == nil { 100 if !gogoproto.IsNullable(f) { 101 d.genCopyFunc("&m."+fName, "&o."+fName) 102 } else { 103 d.P("if o.", fName, " != nil {") 104 d.In() 105 // allocate dst object 106 d.P("m.", fName, " = &", d.TypeName(d.ObjectNamed(f.GetTypeName())), "{}") 107 // copy into the allocated struct 108 d.genCopyFunc("m."+fName, "o."+fName) 109 110 d.Out() 111 d.P("}") 112 } 113 continue 114 } 115 } 116 117 // Handle repeated field 118 if f.IsRepeated() { 119 d.genRepeated(m, f) 120 continue 121 } 122 123 // Handle bytes 124 if f.IsBytes() { 125 d.genCopyBytes("m."+fName, "o."+fName) 126 continue 127 } 128 129 // skip: field was a scalar handled by shallow copy! 130 } 131 132 for i, oo := range m.GetOneofDecl() { 133 d.genOneOf(m, oo, oneofByIndex[i]) 134 } 135 136 d.P("}") 137 d.P() 138 } 139 140 func (d *deepCopyGen) genMap(m *generator.Descriptor, f *descriptor.FieldDescriptorProto) bool { 141 fName := generator.CamelCase(*f.Name) 142 if gogoproto.IsCustomName(f) { 143 fName = gogoproto.GetCustomName(f) 144 } 145 146 dv := d.ObjectNamed(f.GetTypeName()) 147 desc, ok := dv.(*generator.Descriptor) 148 if !ok || !desc.GetOptions().GetMapEntry() { 149 return false 150 } 151 152 mt := d.GoMapType(desc, f) 153 typename := mt.GoType 154 155 d.P("if o.", fName, " != nil {") 156 d.In() 157 d.P("m.", fName, " = make(", typename, ", ", "len(o.", fName, "))") 158 d.P("for k, v := range o.", fName, " {") 159 d.In() 160 if mt.ValueField.IsMessage() { 161 if !gogoproto.IsNullable(f) { 162 d.P("n := ", d.TypeName(d.ObjectNamed(mt.ValueField.GetTypeName())), "{}") 163 d.genCopyFunc("&n", "&v") 164 d.P("m.", fName, "[k] = ", "n") 165 } else { 166 d.P("m.", fName, "[k] = &", d.TypeName(d.ObjectNamed(mt.ValueField.GetTypeName())), "{}") 167 d.genCopyFunc("m."+fName+"[k]", "v") 168 } 169 } else if mt.ValueField.IsBytes() { 170 d.P("m.", fName, "[k] = o.", fName, "[k]") 171 d.genCopyBytes("m."+fName+"[k]", "o."+fName+"[k]") 172 } else { 173 d.P("m.", fName, "[k] = v") 174 } 175 d.Out() 176 d.P("}") 177 d.Out() 178 d.P("}") 179 d.P() 180 181 return true 182 } 183 184 func (d *deepCopyGen) genRepeated(m *generator.Descriptor, f *descriptor.FieldDescriptorProto) { 185 fName := generator.CamelCase(*f.Name) 186 if gogoproto.IsCustomName(f) { 187 fName = gogoproto.GetCustomName(f) 188 } 189 190 typename, _ := d.GoType(m, f) 191 192 d.P("if o.", fName, " != nil {") 193 d.In() 194 d.P("m.", fName, " = make(", typename, ", len(o.", fName, "))") 195 if f.IsMessage() { 196 // TODO(stevvooe): Handle custom type here? 197 goType := d.TypeName(d.ObjectNamed(f.GetTypeName())) // elides [] or * 198 199 d.P("for i := range m.", fName, " {") 200 d.In() 201 if !gogoproto.IsNullable(f) { 202 d.genCopyFunc("&m."+fName+"[i]", "&o."+fName+"[i]") 203 } else { 204 d.P("m.", fName, "[i] = &", goType, "{}") 205 d.genCopyFunc("m."+fName+"[i]", "o."+fName+"[i]") 206 } 207 d.Out() 208 d.P("}") 209 } else if f.IsBytes() { 210 d.P("for i := range m.", fName, " {") 211 d.In() 212 d.genCopyBytes("m."+fName+"[i]", "o."+fName+"[i]") 213 d.Out() 214 d.P("}") 215 } else { 216 d.P("copy(m.", fName, ", ", "o.", fName, ")") 217 } 218 d.Out() 219 d.P("}") 220 d.P() 221 } 222 223 func (d *deepCopyGen) genOneOf(m *generator.Descriptor, oneof *descriptor.OneofDescriptorProto, fields []*descriptor.FieldDescriptorProto) { 224 oneOfName := generator.CamelCase(oneof.GetName()) 225 226 d.P("if o.", oneOfName, " != nil {") 227 d.In() 228 d.P("switch o.", oneOfName, ".(type) {") 229 230 for _, f := range fields { 231 ccTypeName := generator.CamelCaseSlice(m.TypeName()) 232 fName := generator.CamelCase(*f.Name) 233 if gogoproto.IsCustomName(f) { 234 fName = gogoproto.GetCustomName(f) 235 } 236 237 tName := ccTypeName + "_" + fName 238 d.P("case *", tName, ":") 239 d.In() 240 d.P("v := ", tName, " {") 241 d.In() 242 243 var rhs string 244 if f.IsMessage() { 245 goType := d.TypeName(d.ObjectNamed(f.GetTypeName())) // elides [] or * 246 rhs = "&" + goType + "{}" 247 } else if f.IsBytes() { 248 rhs = "make([]byte, len(o.Get" + fName + "()))" 249 } else { 250 rhs = "o.Get" + fName + "()" 251 } 252 d.P(fName, ": ", rhs, ",") 253 d.Out() 254 d.P("}") 255 256 if f.IsMessage() { 257 d.genCopyFunc("v."+fName, "o.Get"+fName+"()") 258 } else if f.IsBytes() { 259 d.genCopyBytes("v."+fName, "o.Get"+fName+"()") 260 } 261 262 d.P("m.", oneOfName, " = &v") 263 d.Out() 264 } 265 266 d.Out() 267 d.P("}") 268 d.Out() 269 d.P("}") 270 d.P() 271 } 272 273 func (d *deepCopyGen) Generate(file *generator.FileDescriptor) { 274 d.PluginImports = generator.NewPluginImports(d.Generator) 275 276 // TODO(stevvooe): Ideally, this could be taken as a parameter to the 277 // deepcopy plugin to control the package import, but this is good enough, 278 // for now. 279 d.copyPkg = d.NewImport("github.com/docker/swarmkit/api/deepcopy") 280 281 d.P() 282 for _, m := range file.Messages() { 283 if m.DescriptorProto.GetOptions().GetMapEntry() { 284 continue 285 } 286 287 if !plugin.DeepcopyEnabled(m.Options) { 288 continue 289 } 290 291 d.genMsgDeepCopy(m) 292 } 293 d.P() 294 }