Skip to content

Commit 4970f67

Browse files
JonasKsTerjeLafton
andcommitted
feat: support for diffing presence containers
Co-authored-by: Terje Lafton <[email protected]>
1 parent 100bd44 commit 4970f67

File tree

6 files changed

+55
-4
lines changed

6 files changed

+55
-4
lines changed

gogen/gogen.go

+14
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,12 @@ func (t *{{ .ParentReceiver }}) To_{{ .Name }}(i interface{}) ({{ .Name }}, erro
838838
{{- end -}}
839839
]", i, i)
840840
}
841+
`)
842+
// presenceMethodTemplate provides a template to output a method
843+
// indicating this is a presence container
844+
presenceMethodTemplate = mustMakeTemplate("presenceMethodTemplate", `
845+
// IsPresence returns nothing, but indicates that the receiver is a presence container.
846+
func (t *{{ .StructName }}) IsPresence() {}
841847
`)
842848
)
843849

@@ -1403,6 +1409,14 @@ func writeGoStruct(targetStruct *ygen.ParsedDirectory, goStructElements map[stri
14031409
errs = append(errs, err)
14041410
}
14051411

1412+
if goOpts.AddYangPresence {
1413+
if targetStruct.PresenceContainer {
1414+
if err := presenceMethodTemplate.Execute(&methodBuf, structDef); err != nil {
1415+
errs = append(errs, err)
1416+
}
1417+
}
1418+
}
1419+
14061420
return GoStructCodeSnippet{
14071421
StructName: structDef.StructName,
14081422
StructDef: structBuf.String(),

ygen/directory.go

+10
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,16 @@ func getOrderedDirDetails(langMapper LangMapper, directory map[string]*Directory
193193
}
194194
default:
195195
pd.Type = Container
196+
if len(dir.Entry.Extra["presence"]) > 0 {
197+
if v := dir.Entry.Extra["presence"][0].(*yang.Value); v != nil {
198+
pd.PresenceContainer = true
199+
} else {
200+
return nil, fmt.Errorf(
201+
"unable to retrieve presence statement, expected non-nil *yang.Value, got %v",
202+
dir.Entry.Extra["presence"][0]
203+
)
204+
}
205+
}
196206
}
197207

198208
for i, entry := 0, dir.Entry; ; i++ {

ygen/ir.go

+2
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ type ParsedDirectory struct {
468468
//
469469
// https://github.com/openconfig/public/blob/master/release/models/openconfig-extensions.yang#L154
470470
CompressedTelemetryAtomic bool
471+
// PresenceContainer indicates that this container is a YANG presence container
472+
PresenceContainer bool
471473
}
472474

473475
// OrderedFieldNames returns the YANG name of all fields belonging to the

ygot/diff.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ func findSetLeaves(s GoStruct, orderedMapAsLeaf bool, opts ...DiffOpt) (map[*pat
254254
return
255255
}
256256

257+
isYangPresence := util.IsYangPresence(ni.StructField)
258+
257259
var sp [][]string
258260
if pathOpt != nil && pathOpt.PreferShadowPath {
259261
// Try the shadow-path tag first to see if it exists.
@@ -314,7 +316,9 @@ func findSetLeaves(s GoStruct, orderedMapAsLeaf bool, opts ...DiffOpt) (map[*pat
314316
// treating it as a leaf (since it is assumed to be
315317
// telemetry-atomic in order to preserve ordering of entries).
316318
if (!isOrderedMap || !orderedMapAsLeaf) && util.IsValueStructPtr(ni.FieldValue) {
317-
return
319+
if !isYangPresence {
320+
return
321+
}
318322
}
319323
if isOrderedMap && orderedMap.Len() == 0 {
320324
return
@@ -334,9 +338,17 @@ func findSetLeaves(s GoStruct, orderedMapAsLeaf bool, opts ...DiffOpt) (map[*pat
334338
}
335339
}
336340

337-
outs := out.(map[*pathSpec]interface{})
338-
outs[vp] = ival
339-
341+
// If the current field is tagged as a presence container,
342+
// we set it's value to `nil` instead of returning earlier.
343+
// This is because empty presence containers has a meaning,
344+
// unlike a normal container.
345+
if isYangPresence {
346+
outs := out.(map[*pathSpec]interface{})
347+
outs[vp] = nil
348+
} else {
349+
outs := out.(map[*pathSpec]interface{})
350+
outs[vp] = ival
351+
}
340352
if isOrderedMap && orderedMapAsLeaf {
341353
// We treat the ordered map as a leaf, so don't
342354
// traverse any descendant elements.

ygot/render.go

+5
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,11 @@ func marshalStructOrOrderedList(s any, enc gnmipb.Encoding, cfg *RFC7951JSONConf
918918
if reflect.ValueOf(s).IsNil() {
919919
return nil, nil
920920
}
921+
// A presence container might not be empty, but we should still
922+
// treat it as such
923+
if _, ok := s.(PresenceContainer); ok {
924+
return nil, nil
925+
}
921926

922927
var (
923928
j any

ygot/types.go

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ import (
1919
"reflect"
2020
)
2121

22+
// PresenceContainer is an interface which can be implemented by Go structs that are
23+
// generated to represent a YANG presence container.
24+
type PresenceContainer interface {
25+
// IsPresence is a marker method that indicates that the struct
26+
// implements the PresenceContainer interface.
27+
IsPresence()
28+
}
29+
2230
// GoStruct is an interface which can be implemented by Go structs that are
2331
// generated to represent a YANG container or list member. It simply allows
2432
// handling code to ensure that it is interacting with a struct that will meet

0 commit comments

Comments
 (0)