>(8-8) + 1<<8
+// octet + 256
+//
+// got to parent idx:
+// (octet+256)>>1 == octet>>1 + 128
func OctetToIdx(octet uint8) uint8 {
- return 128 + octet>>1
+ // use '|' instead of '+', maybe a little bit faster
+ return octet>>1 | 128
}
// IdxToPfx returns the octet and prefix len of baseIdx.
diff --git a/vendor/github.com/gaissmai/bart/internal/bitset/bitset256.go b/vendor/github.com/gaissmai/bart/internal/bitset/bitset256.go
index 1fc0568f63..5e4f70f9ff 100644
--- a/vendor/github.com/gaissmai/bart/internal/bitset/bitset256.go
+++ b/vendor/github.com/gaissmai/bart/internal/bitset/bitset256.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
// Package bitset provides a compact and efficient implementation of a fixed-length
@@ -24,9 +24,9 @@ package bitset
// can inline (*BitSet256).FirstSet with cost 79
// can inline (*BitSet256).Intersects with cost 48
// can inline (*BitSet256).Intersection with cost 53
-// can inline (*BitSet256).IntersectionTop with cost 42
+// can inline (*BitSet256).IntersectionTop with cost 67
// can inline (*BitSet256).IsEmpty with cost 22
-// can inline (*BitSet256).LastSet with cost 37
+// can inline (*BitSet256).LastSet with cost 75
// can inline (*BitSet256).NextSet with cost 65
// can inline (*BitSet256).Rank with cost 57
// can inline (*BitSet256).Set with cost 12
@@ -55,20 +55,21 @@ import (
// not factored out as functions to make most of the methods
// inlineable with minimal costs.
-// BitSet256 represents a fixed size bitset from [0..255]
+// BitSet256 represents a fixed-size bitset for the range [0..255],
+// stored as four uint64 words (256 bits total).
type BitSet256 [4]uint64
-// Set sets the bit.
+// Set sets the bit at position bit (0..255).
func (b *BitSet256) Set(bit uint8) {
b[bit>>6] |= 1 << (bit & 63)
}
-// Clear clears the bit.
+// Clear clears the bit at position bit (0..255).
func (b *BitSet256) Clear(bit uint8) {
b[bit>>6] &^= 1 << (bit & 63)
}
-// Test if the bit is set.
+// Test reports whether the bit at position bit (0..255) is set.
func (b *BitSet256) Test(bit uint8) (ok bool) {
return b[bit>>6]&(1<<(bit&63)) != 0
}
@@ -160,7 +161,7 @@ func (b *BitSet256) NextSet(bit uint8) (next uint8, ok bool) {
//
// It searches the bitset in descending order and returns the position of the
// first bit (top bit) with value 1. If at least one bit is set, ok is true.
-// If no bits are set, ok is false and last is undefined.
+// If no bits are set, ok is false and last is 0.
//
// Example:
//
@@ -170,43 +171,40 @@ func (b *BitSet256) NextSet(bit uint8) (next uint8, ok bool) {
// bs.Set(214)
// index, ok := bs.LastSet() // index == 214, ok == true
func (b *BitSet256) LastSet() (last uint8, ok bool) {
- // optimized for pipelining, sorry, can't inline, cost 81>80
- // try it again when Go supports SIMD intrinsics
- //
- // ### b3 := bits.Len64(b[3])
- // ### b2 := bits.Len64(b[2])
- // ### b1 := bits.Len64(b[1])
- // ### b0 := bits.Len64(b[0])
-
- // ### if b3 != 0 {
- // ### return uint8(b3 + 191), true
- // ### }
- // ### if b2 != 0 {
- // ### return uint8(b2 + 127), true
- // ### }
- // ### if b1 != 0 {
- // ### return uint8(b1 + 63), true
- // ### }
- // ### if b0 != 0 {
- // ### return uint8(b0 - 1), true
- // ### }
- // ### return
-
- for wIdx := 3; wIdx >= 0; wIdx-- {
- if word := b[wIdx]; word != 0 {
- //nolint:gosec // G115: integer overflow conversion int -> uint
- return uint8(wIdx<<6 + bits.Len64(word) - 1), true
- }
+ // optimized by unrolling the loop.
+ // This enables compiler inlining and is ~20% faster.
+ if b[3] != 0 {
+ //nolint:gosec // G115: integer overflow conversion int -> uint
+ return uint8(bits.Len64(b[3]) + 191), true
}
- return
+ if b[2] != 0 {
+ //nolint:gosec // G115: integer overflow conversion int -> uint
+ return uint8(bits.Len64(b[2]) + 127), true
+ }
+ if b[1] != 0 {
+ //nolint:gosec // G115: integer overflow conversion int -> uint
+ return uint8(bits.Len64(b[1]) + 63), true
+ }
+ if b[0] != 0 {
+ //nolint:gosec // G115: integer overflow conversion int -> uint
+ return uint8(bits.Len64(b[0]) - 1), true
+ }
+ return 0, false
}
-// AsSlice returns a slice containing all set bits in the BitSet256.
+// AsSlice extracts the indices of all set bits in the BitSet256, returning them
+// as uint8 values in strictly ascending order.
//
-// The bits are returned in ascending order as uint8 values. The provided buf
-// must be a pointer to an array of 256 uint8s; it is used as backing
-// storage for the result to avoid heap allocations. The returned slice shares
-// its backing array with buf and is only valid until buf is modified or reused.
+// Performance Considerations:
+// To guarantee zero heap allocations and enable compiler inlining, the caller must
+// provide a pointer to a 256-byte array (`buf`) as backing storage. The method
+// populates this array in-place and returns a sliced view (`[]uint8`) tailored to
+// the actual number of set bits.
+//
+// Safety and Lifecycle:
+// The returned slice directly shares the underlying storage of `buf` and is only
+// valid until `buf` is modified or reused. This pattern is highly recommended for
+// hot paths and performance-critical loops where heap churn must be avoided.
func (b *BitSet256) AsSlice(buf *[256]uint8) []uint8 {
size := 0
for wIdx, word := range b {
@@ -217,30 +215,41 @@ func (b *BitSet256) AsSlice(buf *[256]uint8) []uint8 {
}
}
+ // tailor to the actual number of set bits
return buf[:size]
}
-// Bits returns a slice containing all set bits in the BitSet256.
-//
-// The bits are returned in ascending order as uint8 values. Bits allocates
-// a new slice on the heap for the result. For allocation-free collection,
-// use [AsSlice] with a pre-allocated buffer.
+// Bits returns a slice containing the indices of all set bits in strictly
+// ascending order as uint8 values.
//
-// Example usage:
+// Performance Considerations:
+// Unlike [AsSlice], this method dynamically allocates a new slice on the
+// heap to store the result. It is designed for convenience and APIs where the lifecycle
+// of the returned slice needs to outlive the immediate caller's stack frame.
//
-// bits := b.Bits()
-// // bits now contains the indices of all set bits in b
+// Usage Guidance:
+// Use Bits when convenience is preferred over raw performance, or when the result
+// must be returned across boundaries where stack-allocated buffers cannot safely escape.
+// For high-throughput or allocation-free processing, prefer [AsSlice].
func (b *BitSet256) Bits() []uint8 {
return b.AsSlice(&[256]uint8{})
}
-// IntersectionTop computes the intersection of base set with the compare set.
-// If the result set isn't empty, it returns the top most set bit and true.
+// IntersectionTop computes the intersection of the receiver with c
+// and returns the highest (top-most) set bit of the result.
+// If the intersection is non-empty, it returns the top bit index and true.
+// If the intersection is empty, ok is false and top is 0.
func (b *BitSet256) IntersectionTop(c *BitSet256) (top uint8, ok bool) {
- for wIdx := 3; wIdx >= 0; wIdx-- {
- if word := b[wIdx] & c[wIdx]; word != 0 {
+ // optimized by unrolling the first word check.
+ // This enables compiler inlining and is ~15% faster.
+ if w := b[3] & c[3]; w != 0 {
+ //nolint:gosec // G115: integer overflow conversion int -> uint8
+ return uint8(191 + bits.Len64(w)), true
+ }
+ for wIdx := 2; wIdx >= 0; wIdx-- {
+ if w := b[wIdx] & c[wIdx]; w != 0 {
//nolint:gosec // G115: integer overflow conversion int -> uint8
- return uint8(wIdx<<6 + bits.Len64(word) - 1), true
+ return uint8(wIdx<<6 + bits.Len64(w) - 1), true
}
}
return
@@ -276,13 +285,12 @@ func (b *BitSet256) Rank(idx uint8) (rnk int) {
return
}
-// IsEmpty returns true if no bit is set.
+// IsEmpty reports whether all 256 bits are zero.
func (b *BitSet256) IsEmpty() bool {
return b[0]|b[1]|b[2]|b[3] == 0
}
-// Intersects returns true if the intersection of base set with the compare set
-// is not the empty set.
+// Intersects reports whether the receiver and c have at least one bit in common.
func (b *BitSet256) Intersects(c *BitSet256) bool {
return b[0]&c[0] != 0 ||
b[1]&c[1] != 0 ||
@@ -290,8 +298,8 @@ func (b *BitSet256) Intersects(c *BitSet256) bool {
b[3]&c[3] != 0
}
-// Intersection computes the intersection of base set with the compare set.
-// This is the BitSet equivalent of & (and).
+// Intersection returns a new BitSet256 containing only the bits
+// that are set in both the receiver and c (bitwise AND).
func (b *BitSet256) Intersection(c *BitSet256) (bs BitSet256) {
bs[0] = b[0] & c[0]
bs[1] = b[1] & c[1]
@@ -300,8 +308,7 @@ func (b *BitSet256) Intersection(c *BitSet256) (bs BitSet256) {
return
}
-// Union performs an in-place union of the receiver with c.
-// It is the BitSet equivalent of | (OR).
+// Union sets all bits in the receiver that are set in c (in-place bitwise OR).
func (b *BitSet256) Union(c *BitSet256) {
b[0] |= c[0]
b[1] |= c[1]
@@ -309,7 +316,7 @@ func (b *BitSet256) Union(c *BitSet256) {
b[3] |= c[3]
}
-// Size is the number of set bits.
+// Size returns the population count, i.e. the number of set bits.
func (b *BitSet256) Size() (cnt int) {
cnt += bits.OnesCount64(b[0])
cnt += bits.OnesCount64(b[1])
diff --git a/vendor/github.com/gaissmai/bart/internal/lpm/generate_lookuptbl.go b/vendor/github.com/gaissmai/bart/internal/lpm/generate_lookuptbl.go
index 5585a3cc63..44d34a0792 100644
--- a/vendor/github.com/gaissmai/bart/internal/lpm/generate_lookuptbl.go
+++ b/vendor/github.com/gaissmai/bart/internal/lpm/generate_lookuptbl.go
@@ -2,7 +2,7 @@
//go:generate go run $GOFILE
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
// Package main generates a lookup table for longest-prefix-match (LPM) operations
@@ -203,7 +203,7 @@ func genLookupTbl() string {
// - Warnings about not mutating the read-only table
const codeTemplate = `// Code generated by {{.File}}; DO NOT EDIT.
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
// Package lpm (longest-prefix-match) contains the lookup table with which
diff --git a/vendor/github.com/gaissmai/bart/internal/lpm/lookuptblgenerated.go b/vendor/github.com/gaissmai/bart/internal/lpm/lookuptblgenerated.go
index 5c82dbc7fc..8d89b79fd5 100644
--- a/vendor/github.com/gaissmai/bart/internal/lpm/lookuptblgenerated.go
+++ b/vendor/github.com/gaissmai/bart/internal/lpm/lookuptblgenerated.go
@@ -1,6 +1,6 @@
// Code generated by generate_lookuptbl.go; DO NOT EDIT.
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
// Package lpm (longest-prefix-match) contains the lookup table with which
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/bart.go b/vendor/github.com/gaissmai/bart/internal/nodes/bart.go
index f5ab169211..0e2d1e70bf 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/bart.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/bart.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package nodes
@@ -8,32 +8,33 @@ import (
"github.com/gaissmai/bart/internal/lpm"
"github.com/gaissmai/bart/internal/sparse"
- "github.com/gaissmai/bart/internal/value"
)
-// BartNode is a trie level node in the multibit routing table.
+// BartNode represents a single trie level in the multibit routing table.
//
-// Each BartNode contains two conceptually different arrays:
-// - Prefixes stores routing entries (prefix -> value),
-// laid out as a complete binary tree using the baseIndex()
-// function from the ART algorithm.
-// - Children: holding subtries or path-compressed leaves/fringes with
-// a branching factor of 256 (8 bits per stride).
-// - Children holds subnodes for the 256 possible next-hop paths
-// at this trie level (8-bit stride).
+// Unlike the original ART algorithm, this implementation uses popcount-compressed
+// sparse arrays instead of fixed-size allocations. Insertions and lookups rely on
+// fast bitset operations and precomputed lookup tables to maximize CPU pipelining
+// and cache efficiency.
//
-// Entries in Children may be:
-// - *BartNode[V] -> internal child node for further traversal
-// - *LeafNode[V] -> path-comp. node (depth < maxDepth - 1)
-// - *FringeNode[V] -> path-comp. node (depth == maxDepth - 1, stride-aligned: /8, /16, ... /128)
+// Each BartNode maintains two distinct sparse arrays:
//
-// Note: Both *LeafNode and *FringeNode entries are only created by path compression.
-// Prefixes that match exactly at the maximum trie depth (depth == maxDepth) are
-// never stored as Children, but always directly in the prefixes array at that level.
+// 1. Prefixes: Stores routing entries (prefix -> value) for the current stride.
+// These are laid out as a complete binary tree using the baseIndex()
+// function mapping from the ART algorithm. Prefixes that match exactly at
+// the maximum trie depth are always stored here.
//
-// Unlike the original ART, this implementation uses popcount-compressed sparse arrays
-// instead of fixed-size arrays. Array slots are not pre-allocated; insertion
-// and lookup rely on fast bitset operations and precomputed rank indexes.
+// 2. Children: Holds pointers to the next logical levels with a branching
+// factor of 256 (8 bits per stride).
+//
+// A slot in the Children array may contain one of three types:
+// - *BartNode[V]: An internal intermediate node for further trie traversal.
+// - *FringeNode[V]: A path-compressed node if it qualifies as fringe [IsFringe]
+// - *LeafNode[V]: A path-compressed node otherwise.
+//
+// Note: LeafNode and FringeNode are created through path compression and
+// are automatically split into regular BartNodes when a more specific prefix
+// is inserted that requires further branching.
type BartNode[V any] struct {
Prefixes sparse.Array256[V]
Children sparse.Array256[any]
@@ -63,7 +64,8 @@ func (n *BartNode[V]) ChildCount() int {
// It returns true if a prefix already existed at that index (indicating an update),
// false if this is a new insertion.
func (n *BartNode[V]) InsertPrefix(idx uint8, val V) (exists bool) {
- return n.Prefixes.InsertAt(idx, val)
+ _, exists = n.Prefixes.InsertAt(idx, val)
+ return
}
// GetPrefix retrieves the value associated with the prefix at the given index.
@@ -83,9 +85,8 @@ func (n *BartNode[V]) MustGetPrefix(idx uint8) (val V) {
func (n *BartNode[V]) AllIndices() iter.Seq2[uint8, V] {
return func(yield func(uint8, V) bool) {
var buf [256]uint8
- for _, idx := range n.Prefixes.AsSlice(&buf) {
- val := n.MustGetPrefix(idx)
- if !yield(idx, val) {
+ for i, idx := range n.Prefixes.AsSlice(&buf) {
+ if !yield(idx, n.Prefixes.Items[i]) {
return
}
}
@@ -103,7 +104,8 @@ func (n *BartNode[V]) DeletePrefix(idx uint8) (exists bool) {
// The child can be a *BartNode[V], *LeafNode[V], or *FringeNode[V].
// Returns true if a child already existed at that address.
func (n *BartNode[V]) InsertChild(addr uint8, child any) (exists bool) {
- return n.Children.InsertAt(addr, child)
+ _, exists = n.Children.InsertAt(addr, child)
+ return
}
// GetChild retrieves the child node at the specified address.
@@ -125,8 +127,7 @@ func (n *BartNode[V]) AllChildren() iter.Seq2[uint8, any] {
var buf [256]uint8
addrs := n.Children.AsSlice(&buf)
for i, addr := range addrs {
- child := n.Children.Items[i]
- if !yield(addr, child) {
+ if !yield(addr, n.Children.Items[i]) {
return
}
}
@@ -172,7 +173,7 @@ func (n *BartNode[V]) LookupIdx(idx uint8) (top uint8, val V, ok bool) {
return top, val, ok
}
-// Lookup is just a simple wrapper for lookupIdx.
+// Lookup is just a simple wrapper for LookupIdx.
func (n *BartNode[V]) Lookup(idx uint8) (val V, ok bool) {
_, val, ok = n.LookupIdx(idx)
return val, ok
@@ -188,7 +189,7 @@ func (n *BartNode[V]) Lookup(idx uint8) (val V, ok bool) {
//
// Note: The returned node is a new instance with copied slices but only shallow copies of nested nodes,
// except for LeafNode and FringeNode children which are cloned according to cloneFn.
-func (n *BartNode[V]) CloneFlat(cloneFn value.CloneFunc[V]) *BartNode[V] {
+func (n *BartNode[V]) CloneFlat(cloneFn func(V) V) *BartNode[V] {
if n == nil {
return nil
}
@@ -245,7 +246,7 @@ func (n *BartNode[V]) CloneFlat(cloneFn value.CloneFunc[V]) *BartNode[V] {
//
// Returns a new instance of BartNode[V] which is a complete deep clone of the
// receiver node with all descendants.
-func (n *BartNode[V]) CloneRec(cloneFn value.CloneFunc[V]) *BartNode[V] {
+func (n *BartNode[V]) CloneRec(cloneFn func(V) V) *BartNode[V] {
if n == nil {
return nil
}
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/bartmethodsgenerated.go b/vendor/github.com/gaissmai/bart/internal/nodes/bartmethodsgenerated.go
index 69c0e8a1c3..8b92f78f86 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/bartmethodsgenerated.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/bartmethodsgenerated.go
@@ -1,6 +1,6 @@
// Code generated from file "commonmethods_tmpl.go"; DO NOT EDIT.
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package nodes
@@ -17,65 +17,76 @@ import (
"github.com/gaissmai/bart/internal/value"
)
-// Insert inserts a network prefix and its associated value into the
-// trie starting at the specified byte depth.
+// Insert adds or updates a network prefix and its associated value in the trie.
+// Traversal begins at the specified byte depth.
//
-// The function traverses the prefix address from the given depth and inserts
-// the value either directly into the node's prefix table or as a compressed
-// leaf or fringe node. If a conflicting leaf or fringe exists, it creates
-// a new intermediate node to accommodate both entries.
+// The trie utilizes path compression to conserve memory. A prefix is inserted:
+// - Uncompressed into a node's prefix table at depth == strideCount.
+// - As a path-compressed FringeNode if it qualifies as fringe [IsFringe].
+// - As a path-compressed LeafNode otherwise.
+//
+// When a new prefix collides with an existing compressed node (Leaf or Fringe),
+// Insert resolves the collision by creating a new intermediate node, pushing
+// the existing entry down to the next level, and continuing traversal.
//
// Parameters:
-// - pfx: The network prefix to insert (must be in canonical form)
-// - val: The value to associate with the prefix
-// - depth: The current depth in the trie (0-based byte index)
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
//
-// Returns true if a prefix already existed and was updated, false for new insertions.
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
func (n *BartNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *BartNode[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next trie level.
+ n = kid
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(BartNode[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -83,18 +94,17 @@ func (n *BartNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(BartNode[V])
newNode.InsertPrefix(1, kid.Value)
@@ -108,63 +118,74 @@ func (n *BartNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
panic("unreachable")
}
-// InsertPersist is similar to insert but the receiver isn't modified.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *BartNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix, val V, depth int) (exists bool) {
+// InsertPersist adds or updates a network prefix and its associated value in the trie
+// using Copy-On-Write (COW) semantics. Traversal begins at the specified byte depth.
+//
+// Unlike [Insert], InsertPersist ensures structural integrity of the existing tree
+// by cloning internal nodes along the descent path (Copy-On-Write) before mutation.
+//
+// Parameters:
+// - cloneFn: The function used to clone values (V).
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
+//
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
+func (n *BartNode[V]) InsertPersist(cloneFn func(V) V, pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *BartNode[V]:
- // clone the traversed path
-
- // kid points now to cloned kid
+ // Standard intermediate node: Clone the traversed path to maintain persistence (COW).
+ // We clone the child node before modifying it, then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // replace kid with clone
n.InsertChild(octet, kid)
-
n = kid
- continue // descend down to next trie level
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(BartNode[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -172,18 +193,17 @@ func (n *BartNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(BartNode[V])
newNode.InsertPrefix(1, kid.Value)
@@ -193,162 +213,170 @@ func (n *BartNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix
default:
panic("logic error, wrong node type")
}
-
}
-
panic("unreachable")
}
-// PurgeAndCompress performs bottom-up compression of the trie.
+// PurgeAndCompress performs bottom-up trie maintenance to restore path compression
+// after a deletion. It unwinds the provided stack of parent nodes, identifying
+// nodes that have become sparse (i.e., containing only a single prefix or a single
+// child node) and prunes them by promoting the underlying entries to the parent level.
//
-// The function unwinds the provided stack of parent nodes, checking each level
-// for compression opportunities based on child and prefix count.
-// It may convert:
-// - Nodes with a single prefix into leaf one level above.
-// - Nodes with a single leaf or fringe into leaf one level above.
+// This ensures the trie remains memory-efficient by collapsing redundant intermediate
+// nodes back into path-compressed LeafNodes or FringeNodes whenever possible.
//
// Parameters:
-// - stack: Array of parent nodes to process during unwinding
-// - octets: The path of octets taken to reach the current position
-// - is4: True for IPv4 processing, false for IPv6
+// - stack: Array of parent nodes to process during bottom-up unwinding.
+// - octets: The full path of octets leading to the current node.
+// - is4: True for IPv4 processing, false for IPv6.
func (n *BartNode[V]) PurgeAndCompress(stack []*BartNode[V], octets []uint8, is4 bool) {
- // unwind the stack
+ // Iterate backwards through the ancestor stack to prune nodes from the bottom up.
for depth := len(stack) - 1; depth >= 0; depth-- {
parent := stack[depth]
octet := octets[depth]
+ // Check if the current node is redundant.
+ // A node may be redundant if it contains exactly one entry (either a prefix or
+ // a compressed child node).
pfxCount := n.PrefixCount()
childCount := n.ChildCount()
+ // If it contains more than one entry, it is always structurally significant and cannot be pruned.
if pfxCount+childCount > 1 {
return
}
switch {
case childCount == 1:
- singleAddr, _ := n.Children.FirstSet() // single addr must be first bit set
+ // The node has exactly one child. We determine if it is a path node,
+ // a compressed LeafNode, or a compressed FringeNode.
+ singleAddr, _ := n.Children.FirstSet()
anyKid := n.MustGetChild(singleAddr)
switch kid := anyKid.(type) {
case *BartNode[V]:
- // fast exit, we are at an intermediate path node
- // no further delete/compress upwards the stack is possible
+ // The child is an intermediate path node; the tree structure is required
+ // at this level. Compression cannot proceed further up.
return
case *LeafNode[V]:
- // just one leaf, delete this node and reinsert the leaf above
+ // The child is a compressed LeafNode. Prune the current node
+ // and re-insert the leaf into the parent to elevate it.
parent.DeleteChild(octet)
-
- // ... (re)insert the leaf at parents depth
parent.Insert(kid.Prefix, kid.Value, depth)
case *FringeNode[V]:
- // just one fringe, delete this node and reinsert the fringe as leaf above
+ // The child is a compressed FringeNode. Prune the current node
+ // and re-insert the fringe as a leaf into the parent.
parent.DeleteChild(octet)
- // rebuild the prefix with octets, depth, ip version and addr
- // depth is the parent's depth, so add +1 here for the kid
- // lastOctet in cidrForFringe is the only addr (singleAddr)
+ // Reconstruct the full prefix for the fringe, as path compression
+ // requires the entire CIDR path, not just the remainder.
+ // depth is the parent's depth, so we offset by 1 for the kid's position.
fringePfx := CidrForFringe(octets, depth+1, is4, singleAddr)
- // ... (re)reinsert prefix/value at parents depth
parent.Insert(fringePfx, kid.Value, depth)
}
case pfxCount == 1:
- // just one prefix, delete this node and reinsert the idx as leaf above
+ // The node has exactly one prefix. Prune the node and elevate the
+ // prefix to the parent level as a leaf/fringe.
parent.DeleteChild(octet)
- // get prefix back from idx ...
- idx, _ := n.Prefixes.FirstSet() // single idx must be first bit set
+ // Retrieve the single prefix stored in this node.
+ idx, _ := n.Prefixes.FirstSet()
val := n.MustGetPrefix(idx)
- // ... and octet path
+ // Reconstruct the prefix from the path for re-insertion.
path := StridePath{}
copy(path[:], octets)
-
- // depth is the parent's depth, so add +1 here for the kid
pfx := CidrFromPath(path, depth+1, is4, idx)
- // ... (re)insert prefix/value at parents depth
parent.Insert(pfx, val, depth)
+ default:
+ panic("unreachable")
}
- // climb up the stack
+ // Move up to the next parent in the stack to continue pruning.
n = parent
}
}
-// Delete deletes the prefix and returns true if the prefix existed,
-// or false otherwise. The prefix must be in canonical form.
+// Delete removes the prefix from the trie rooted at n and returns true if the
+// prefix existed, false if it was not found. The prefix must be in canonical
+// (masked) form.
+//
+// The trie uses path compression, so a prefix may be stored in one of three ways:
+// - In the current node's prefix table when the prefix length aligns exactly
+// with the stride boundary at this depth (depth == strideCount).
+// - As a path-compressed FringeNode in a child slot for stride-aligned prefixes
+// (e.g. /8, /16, /24); occurs at depth == strideCount-1.
+// - As a path-compressed LeafNode in a child slot for prefixes otherwise.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
func (n *BartNode[V]) Delete(pfx netip.Prefix) (exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
- ip := pfx.Addr()
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // record the nodes on the path to the deleted node, needed to purge
- // and/or path compress nodes after the deletion of a prefix
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
stack := [MaxTreeDepth]*BartNode[V]{}
- // find the trie node
for depth, octet := range octets {
- depth = depth & DepthMask // BCE, Delete must be fast
+ depth &= DepthMask // BCE hint; keep Delete on the fast path
- // push current node on stack for path recording
- stack[depth] = n
+ stack[depth] = n // record current node before descending
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- // try to delete prefix in trie node
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
return true
}
+ // no child node exists at this octet; the prefix is not in the trie
if !n.Children.Test(octet) {
return false
}
+
+ // A child node exists at this octet path, retrieve it.
kid := n.MustGetChild(octet)
- // kid is node or leaf or fringe at octet
switch kid := kid.(type) {
case *BartNode[V]:
- n = kid // descend down to next trie level
+ n = kid // descend to the next trie level
case *FringeNode[V]:
- // if pfx is no fringe at this depth, fast exit
- if !IsFringe(depth, pfx) {
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // pfx is fringe at depth, delete fringe
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Attention: pfx must be masked to be comparable!
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
return false
}
- // prefix is equal leaf, delete leaf
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
@@ -359,142 +387,150 @@ func (n *BartNode[V]) Delete(pfx netip.Prefix) (exists bool) {
panic("unreachable")
}
-// DeletePersist is similar to delete but does not mutate the original trie.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *BartNode[V]) DeletePersist(cloneFn value.CloneFunc[V], pfx netip.Prefix) (exists bool) {
- ip := pfx.Addr() // the pfx must be in canonical form
+// DeletePersist removes the prefix from the trie rooted at n using Copy-On-Write (COW) semantics.
+// It returns true if the prefix existed, false if it was not found. The prefix must be in
+// canonical (masked) form.
+//
+// Like [Delete], this method uses path compression. However, DeletePersist ensures
+// the structural integrity of the existing tree by cloning internal nodes along the
+// descent path (COW) before mutation.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
+func (n *BartNode[V]) DeletePersist(cloneFn func(V) V, pfx netip.Prefix) (exists bool) {
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // Stack to keep track of cloned nodes along the path,
- // needed for purge and path compression after delete.
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
+ // Since this is a COW operation, we store the cloned nodes here.
stack := [MaxTreeDepth]*BartNode[V]{}
- // Traverse the trie to locate the prefix to delete.
for depth, octet := range octets {
- // Keep track of the cloned node at current depth.
- stack[depth] = n
+ depth &= DepthMask // BCE hint; keep DeletePersist on the fast path
+ stack[depth] = n // record current node before descending
- if depth == lastOctetPlusOne {
- // Attempt to delete the prefix from the node's prefixes.
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
- // Prefix not found, nothing deleted.
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // After deletion, purge nodes and compress the path if needed.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
}
- addr := octet
-
- // If child node doesn't exist, no prefix to delete.
- if !n.Children.Test(addr) {
+ // no child node exists at this octet; the prefix is not in the trie
+ if !n.Children.Test(octet) {
return false
}
- // Fetch child node at current address.
- kid := n.MustGetChild(addr)
+ // A child node exists at this octet path, retrieve it to either continue
+ // our descent or perform a persistent delete on a compressed node.
+ kid := n.MustGetChild(octet)
switch kid := kid.(type) {
case *BartNode[V]:
- // Clone the internal node for copy-on-write.
+ // Standard intermediate node: Clone the traversed path to maintain
+ // persistence (COW). We clone the child node before modifying it,
+ // then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // Replace child with cloned node.
- n.InsertChild(addr, kid)
-
- // Descend to cloned child node.
+ n.InsertChild(octet, kid)
n = kid
continue
case *FringeNode[V]:
- // Reached a path compressed fringe.
- if !IsFringe(depth, pfx) {
- // Prefix to delete not found here.
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // Delete the fringe node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Reached a path compressed leaf node.
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
- // Leaf prefix does not match; nothing to delete.
return false
}
- // Delete leaf node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
- // Unexpected node type indicates a logic error.
panic("logic error, wrong node type")
}
}
- // Should never happen: traversal always returns or panics inside loop.
panic("unreachable")
}
// Get retrieves the value associated with the given network prefix.
-// Returns the stored value and true if the prefix exists in this node,
-// zero value and false if the prefix is not found.
+// Traversal descends through the trie using the prefix's octets.
+//
+// The lookup handles path compression transparently:
+// - If the path matches an internal node at the target stride, the value is retrieved
+// from the node's prefix table.
+// - If the path leads to a compressed LeafNode or FringeNode, the function verifies
+// the prefix match before returning the value.
//
// Parameters:
-// - pfx: The network prefix to look up (must be in canonical form)
+// - pfx: The network prefix to look up (must be in canonical form).
//
// Returns:
-// - val: The value associated with the prefix (zero value if not found)
-// - exists: True if the prefix was found, false otherwise
+// - val: The value associated with the prefix (zero value if not found).
+// - exists: True if the prefix was found, false otherwise.
func (n *BartNode[V]) Get(pfx netip.Prefix) (val V, exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
+ // The prefix must be provided in canonical (masked) form for correct trie traversal.
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the trie node
+ // Traverse the trie octet by octet based on the prefix path.
for depth, octet := range octets {
- if depth == lastOctetPlusOne {
- return n.GetPrefix(art.PfxToIdx(octet, lastBits))
+ // At the target stride boundary, the prefix is expected in this node's
+ // prefix table.
+ if depth == strideCount {
+ return n.GetPrefix(art.PfxToIdx(octet, modBits))
}
+ // If no child exists at this path, the prefix is not in the trie.
kidAny, ok := n.GetChild(octet)
if !ok {
return val, false
}
- // kid is node or leaf or fringe at octet
+ // Identify the node type at this path segment.
switch kid := kidAny.(type) {
case *BartNode[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next level.
+ n = kid
case *FringeNode[V]:
- // reached a path compressed fringe, stop traversing
- if IsFringe(depth, pfx) {
+ // Reached a path-compressed FringeNode.
+ // Verify if the prefix qualifies as a fringe at this depth to return a match.
+ if IsFringe(depth, pfxLen) {
return kid.Value, true
}
return val, false
case *LeafNode[V]:
- // reached a path compressed prefix, stop traversing
+ // Reached a path-compressed LeafNode.
+ // Check if the stored prefix matches the lookup prefix exactly.
if kid.Prefix == pfx {
return kid.Value, true
}
@@ -512,7 +548,7 @@ func (n *BartNode[V]) Get(pfx netip.Prefix) (val V, exists bool) {
// The callback receives the current value (if found) and existence flag, and returns
// a new value and deletion flag.
//
-// modify returns the size delta (-1, 0, +1).
+// Modify returns the size delta (-1, 0, +1).
// This method handles path traversal, node creation for new paths, and automatic
// purge/compress operations after deletions.
//
@@ -526,9 +562,10 @@ func (n *BartNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
var zero V
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// record the nodes on the path to the deleted node, needed to purge
// and/or path compress nodes after the deletion of a prefix
@@ -536,16 +573,15 @@ func (n *BartNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
// find the proper trie node to update prefix
for depth, octet := range octets {
- depth = depth & DepthMask // BCE
+ depth &= DepthMask // BCE
// push current node on stack for path recording
stack[depth] = n
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // stride for this prefix. Insert or update it directly in this node's prefix table.
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
oldVal, existed := n.GetPrefix(idx)
newVal, del := cb(oldVal, existed)
@@ -585,7 +621,7 @@ func (n *BartNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
}
// insert
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
n.InsertChild(octet, NewFringeNode(newVal))
} else {
n.InsertChild(octet, NewLeafNode(pfx, newVal))
@@ -644,7 +680,7 @@ func (n *BartNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
case *FringeNode[V]:
// update existing value if prefix is fringe
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
newVal, del := cb(kid.Value, true)
if !del {
kid.Value = newVal
@@ -774,8 +810,8 @@ func (n *BartNode[V]) EqualRec(o *BartNode[V]) bool {
//
// It returns immediately if n is nil or empty. For each visited internal node
// it calls dump to write the node's representation, then iterates its child
-// addresses and recurses into children that implement nodeDumper[V] (internal
-// subnodes). The path slice and depth together represent the byte-wise path
+// addresses and recurses into children of type *BartNode[V] (internal subnodes).
+// The path slice and depth together represent the byte-wise path
// from the root to the current node; depth is incremented for each recursion.
// The is4 flag controls IPv4/IPv6 formatting used by dump.
func (n *BartNode[V]) DumpRec(w io.Writer, path StridePath, depth int, is4 bool) {
@@ -803,8 +839,8 @@ func (n *BartNode[V]) dump(w io.Writer, path StridePath, depth int, is4 bool) {
bits := depth * strideLen
indent := strings.Repeat(".", depth)
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// node type with depth and octet path and bits.
fmt.Fprintf(w, "\n%s[%s] depth: %d path: [%s] / %d\n",
@@ -967,7 +1003,7 @@ func (n *BartNode[V]) DumpString(octets []uint8, depth int, is4 bool) string {
// - stopNode: has children but no subnodes (nodes == 0)
// - halfNode: contains at least one leaf or fringe and also has subnodes, but
// no prefixes
-// - fullNode: has prefixes or leaves/fringes and also has subnodes
+// - fullNode: has prefixes and also has subnodes
// - pathNode: has subnodes only (no prefixes, leaves, or fringes)
//
// The order of these checks is significant to ensure the correct classification.
@@ -1024,7 +1060,7 @@ func (n *BartNode[V]) Stats() (s StatsT) {
// It walks the node tree recursively and sums immediate counts (prefixes and
// child slots) plus the number of nodes, leaves, and fringe nodes in the
// subtree. If n is nil or empty, a zeroed stats is returned. The returned
-// stats.nodes includes the current node. The function will panic if a child
+// SubNodes count includes the current node. The function will panic if a child
// has an unexpected concrete type.
func (n *BartNode[V]) StatsRec() (s StatsT) {
if n == nil || n.IsEmpty() {
@@ -1080,8 +1116,8 @@ func (n *BartNode[V]) FprintRec(w io.Writer, parent TrieItem[V], pad string) err
return CmpPrefix(a.Cidr, b.Cidr)
})
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// for all direct item under this node ...
for i, item := range directItems {
@@ -1178,7 +1214,7 @@ func (n *BartNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
path[depth] = addr
directItems = append(directItems, kid.DirectItemsRec(0, path, depth+1, is4)...)
- case *LeafNode[V]: // path-compressed child, stop's recursion for this child
+ case *LeafNode[V]: // path-compressed child, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1187,7 +1223,7 @@ func (n *BartNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
}
directItems = append(directItems, item)
- case *FringeNode[V]: // path-compressed fringe, stop's recursion for this child
+ case *FringeNode[V]: // path-compressed fringe, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1221,9 +1257,9 @@ func (n *BartNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
// The merge operation is destructive on the receiver n, but leaves the source node o unchanged.
//
// Returns the number of duplicate prefixes that were overwritten during merging.
-func (n *BartNode[V]) UnionRec(cloneFn value.CloneFunc[V], o *BartNode[V], depth int) (duplicates int) {
+func (n *BartNode[V]) UnionRec(cloneFn func(V) V, o *BartNode[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1254,9 +1290,9 @@ func (n *BartNode[V]) UnionRec(cloneFn value.CloneFunc[V], o *BartNode[V], depth
}
// UnionRecPersist is similar to unionRec but performs an immutable union of nodes.
-func (n *BartNode[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *BartNode[V], depth int) (duplicates int) {
+func (n *BartNode[V]) UnionRecPersist(cloneFn func(V) V, o *BartNode[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1305,7 +1341,7 @@ func (n *BartNode[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *BartNode[V]
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *BartNode[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *BartNode[V]) handleMatrix(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*BartNode[V])
@@ -1422,7 +1458,7 @@ func (n *BartNode[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool,
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *BartNode[V]) handleMatrixPersist(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *BartNode[V]) handleMatrixPersist(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*BartNode[V])
@@ -1654,9 +1690,7 @@ func (n *BartNode[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield f
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, childAddr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1691,9 +1725,7 @@ func (n *BartNode[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield f
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, addr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1879,9 +1911,10 @@ func (n *BartNode[V]) EachSubnet(octets []byte, depth int, is4 bool, pfxIdx uint
// the iteration early.
func (n *BartNode[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// stack of the traversed nodes for reverse ordering of supernets
stack := [MaxTreeDepth]*BartNode[V]{}
@@ -1894,7 +1927,7 @@ func (n *BartNode[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V) bo
LOOP:
for depth, octet = range octets {
// stepped one past the last stride of interest; back up to last and exit
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
depth--
break
}
@@ -1955,11 +1988,10 @@ LOOP:
// all others are just host routes
var idx uint8
octet = octets[depth]
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx = art.PfxToIdx(octet, lastBits)
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
+ if depth == strideCount {
+ idx = art.PfxToIdx(octet, modBits)
} else {
idx = art.OctetToIdx(octet)
}
@@ -1996,17 +2028,18 @@ LOOP:
func (n *BartNode[V]) Subnets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
// values derived from pfx
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// find the trie node
for depth, octet := range octets {
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
// so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
n.EachSubnet(octets, depth, is4, idx, yield)
return
}
@@ -2124,7 +2157,7 @@ func (n *BartNode[V]) Overlaps(o *BartNode[V], depth int) bool {
// OverlapsRoutes compares the prefix sets of two nodes (n and o).
//
// It first checks for direct bitset intersection (identical indices),
-// then walks both prefix sets using lpmTest to detect if any
+// then walks both prefix sets using the Contains method to detect if any
// of the n-prefixes is contained in o, or vice versa.
func (n *BartNode[V]) OverlapsRoutes(o *BartNode[V]) bool {
// some prefixes are identical, trivial overlap
@@ -2267,19 +2300,20 @@ func (n *BartNode[V]) OverlapsSameChildren(o *BartNode[V], depth int) bool {
// trie traversal across varying prefix lengths and compression levels.
func (n *BartNode[V]) OverlapsPrefixAtDepth(pfx netip.Prefix, depth int) bool {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
for ; depth < len(octets); depth++ {
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
break
}
octet := octets[depth]
// full octet path in node trie, check overlap with last prefix octet
- if depth == lastOctetPlusOne {
- return n.OverlapsIdx(art.PfxToIdx(octet, lastBits))
+ if depth == strideCount {
+ return n.OverlapsIdx(art.PfxToIdx(octet, modBits))
}
// test if any route overlaps prefix´ so far
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/commonmethods_tmpl.go b/vendor/github.com/gaissmai/bart/internal/nodes/commonmethods_tmpl.go
index bdcee61cb7..6767152e53 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/commonmethods_tmpl.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/commonmethods_tmpl.go
@@ -1,6 +1,6 @@
//go:build generate
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
//go:generate ../../scripts/generate-node-methods.sh
@@ -31,85 +31,96 @@ type _NODE_TYPE[V any] struct {
Children struct{ bitset.BitSet256 }
}
-func (n *_NODE_TYPE[V]) IsEmpty() (_ bool) { return }
-func (n *_NODE_TYPE[V]) PrefixCount() (_ int) { return }
-func (n *_NODE_TYPE[V]) ChildCount() (_ int) { return }
-func (n *_NODE_TYPE[V]) MustGetPrefix(uint8) (_ V) { return }
-func (n *_NODE_TYPE[V]) MustGetChild(uint8) (_ any) { return }
-func (n *_NODE_TYPE[V]) InsertPrefix(uint8, V) (_ bool) { return }
-func (n *_NODE_TYPE[V]) DeletePrefix(uint8) (_ bool) { return }
-func (n *_NODE_TYPE[V]) GetChild(uint8) (_ any, _ bool) { return }
-func (n *_NODE_TYPE[V]) GetPrefix(uint8) (_ V, _ bool) { return }
-func (n *_NODE_TYPE[V]) InsertChild(uint8, any) (_ bool) { return }
-func (n *_NODE_TYPE[V]) DeleteChild(uint8) (_ bool) { return }
-func (n *_NODE_TYPE[V]) CloneRec(value.CloneFunc[V]) (_ *_NODE_TYPE[V]) { return }
-func (n *_NODE_TYPE[V]) CloneFlat(value.CloneFunc[V]) (_ *_NODE_TYPE[V]) { return }
-func (n *_NODE_TYPE[V]) AllIndices() (seq2 iter.Seq2[uint8, V]) { return }
-func (n *_NODE_TYPE[V]) AllChildren() (seq2 iter.Seq2[uint8, any]) { return }
-func (n *_NODE_TYPE[V]) Contains(uint8) (_ bool) { return }
-func (n *_NODE_TYPE[V]) LookupIdx(uint8) (_ uint8, _ V, _ bool) { return }
+func (n *_NODE_TYPE[V]) IsEmpty() (_ bool) { return }
+func (n *_NODE_TYPE[V]) PrefixCount() (_ int) { return }
+func (n *_NODE_TYPE[V]) ChildCount() (_ int) { return }
+func (n *_NODE_TYPE[V]) MustGetPrefix(uint8) (_ V) { return }
+func (n *_NODE_TYPE[V]) MustGetChild(uint8) (_ any) { return }
+func (n *_NODE_TYPE[V]) InsertPrefix(uint8, V) (_ bool) { return }
+func (n *_NODE_TYPE[V]) DeletePrefix(uint8) (_ bool) { return }
+func (n *_NODE_TYPE[V]) GetChild(uint8) (_ any, _ bool) { return }
+func (n *_NODE_TYPE[V]) GetPrefix(uint8) (_ V, _ bool) { return }
+func (n *_NODE_TYPE[V]) InsertChild(uint8, any) (_ bool) { return }
+func (n *_NODE_TYPE[V]) DeleteChild(uint8) (_ bool) { return }
+func (n *_NODE_TYPE[V]) CloneRec(func(V) V) (_ *_NODE_TYPE[V]) { return }
+func (n *_NODE_TYPE[V]) CloneFlat(func(V) V) (_ *_NODE_TYPE[V]) { return }
+func (n *_NODE_TYPE[V]) AllIndices() (seq2 iter.Seq2[uint8, V]) { return }
+func (n *_NODE_TYPE[V]) AllChildren() (seq2 iter.Seq2[uint8, any]) { return }
+func (n *_NODE_TYPE[V]) Contains(uint8) (_ bool) { return }
+func (n *_NODE_TYPE[V]) LookupIdx(uint8) (_ uint8, _ V, _ bool) { return }
// ### GENERATE DELETE END ###
-// Insert inserts a network prefix and its associated value into the
-// trie starting at the specified byte depth.
+// Insert adds or updates a network prefix and its associated value in the trie.
+// Traversal begins at the specified byte depth.
//
-// The function traverses the prefix address from the given depth and inserts
-// the value either directly into the node's prefix table or as a compressed
-// leaf or fringe node. If a conflicting leaf or fringe exists, it creates
-// a new intermediate node to accommodate both entries.
+// The trie utilizes path compression to conserve memory. A prefix is inserted:
+// - Uncompressed into a node's prefix table at depth == strideCount.
+// - As a path-compressed FringeNode if it qualifies as fringe [IsFringe].
+// - As a path-compressed LeafNode otherwise.
+//
+// When a new prefix collides with an existing compressed node (Leaf or Fringe),
+// Insert resolves the collision by creating a new intermediate node, pushing
+// the existing entry down to the next level, and continuing traversal.
//
// Parameters:
-// - pfx: The network prefix to insert (must be in canonical form)
-// - val: The value to associate with the prefix
-// - depth: The current depth in the trie (0-based byte index)
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
//
-// Returns true if a prefix already existed and was updated, false for new insertions.
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
func (n *_NODE_TYPE[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *_NODE_TYPE[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next trie level.
+ n = kid
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(_NODE_TYPE[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -117,18 +128,17 @@ func (n *_NODE_TYPE[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool)
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(_NODE_TYPE[V])
newNode.InsertPrefix(1, kid.Value)
@@ -142,63 +152,74 @@ func (n *_NODE_TYPE[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool)
panic("unreachable")
}
-// InsertPersist is similar to insert but the receiver isn't modified.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *_NODE_TYPE[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix, val V, depth int) (exists bool) {
+// InsertPersist adds or updates a network prefix and its associated value in the trie
+// using Copy-On-Write (COW) semantics. Traversal begins at the specified byte depth.
+//
+// Unlike [Insert], InsertPersist ensures structural integrity of the existing tree
+// by cloning internal nodes along the descent path (Copy-On-Write) before mutation.
+//
+// Parameters:
+// - cloneFn: The function used to clone values (V).
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
+//
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
+func (n *_NODE_TYPE[V]) InsertPersist(cloneFn func(V) V, pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *_NODE_TYPE[V]:
- // clone the traversed path
-
- // kid points now to cloned kid
+ // Standard intermediate node: Clone the traversed path to maintain persistence (COW).
+ // We clone the child node before modifying it, then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // replace kid with clone
n.InsertChild(octet, kid)
-
n = kid
- continue // descend down to next trie level
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(_NODE_TYPE[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -206,18 +227,17 @@ func (n *_NODE_TYPE[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Pref
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(_NODE_TYPE[V])
newNode.InsertPrefix(1, kid.Value)
@@ -227,162 +247,170 @@ func (n *_NODE_TYPE[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Pref
default:
panic("logic error, wrong node type")
}
-
}
-
panic("unreachable")
}
-// PurgeAndCompress performs bottom-up compression of the trie.
+// PurgeAndCompress performs bottom-up trie maintenance to restore path compression
+// after a deletion. It unwinds the provided stack of parent nodes, identifying
+// nodes that have become sparse (i.e., containing only a single prefix or a single
+// child node) and prunes them by promoting the underlying entries to the parent level.
//
-// The function unwinds the provided stack of parent nodes, checking each level
-// for compression opportunities based on child and prefix count.
-// It may convert:
-// - Nodes with a single prefix into leaf one level above.
-// - Nodes with a single leaf or fringe into leaf one level above.
+// This ensures the trie remains memory-efficient by collapsing redundant intermediate
+// nodes back into path-compressed LeafNodes or FringeNodes whenever possible.
//
// Parameters:
-// - stack: Array of parent nodes to process during unwinding
-// - octets: The path of octets taken to reach the current position
-// - is4: True for IPv4 processing, false for IPv6
+// - stack: Array of parent nodes to process during bottom-up unwinding.
+// - octets: The full path of octets leading to the current node.
+// - is4: True for IPv4 processing, false for IPv6.
func (n *_NODE_TYPE[V]) PurgeAndCompress(stack []*_NODE_TYPE[V], octets []uint8, is4 bool) {
- // unwind the stack
+ // Iterate backwards through the ancestor stack to prune nodes from the bottom up.
for depth := len(stack) - 1; depth >= 0; depth-- {
parent := stack[depth]
octet := octets[depth]
+ // Check if the current node is redundant.
+ // A node may be redundant if it contains exactly one entry (either a prefix or
+ // a compressed child node).
pfxCount := n.PrefixCount()
childCount := n.ChildCount()
+ // If it contains more than one entry, it is always structurally significant and cannot be pruned.
if pfxCount+childCount > 1 {
return
}
switch {
case childCount == 1:
- singleAddr, _ := n.Children.FirstSet() // single addr must be first bit set
+ // The node has exactly one child. We determine if it is a path node,
+ // a compressed LeafNode, or a compressed FringeNode.
+ singleAddr, _ := n.Children.FirstSet()
anyKid := n.MustGetChild(singleAddr)
switch kid := anyKid.(type) {
case *_NODE_TYPE[V]:
- // fast exit, we are at an intermediate path node
- // no further delete/compress upwards the stack is possible
+ // The child is an intermediate path node; the tree structure is required
+ // at this level. Compression cannot proceed further up.
return
case *LeafNode[V]:
- // just one leaf, delete this node and reinsert the leaf above
+ // The child is a compressed LeafNode. Prune the current node
+ // and re-insert the leaf into the parent to elevate it.
parent.DeleteChild(octet)
-
- // ... (re)insert the leaf at parents depth
parent.Insert(kid.Prefix, kid.Value, depth)
case *FringeNode[V]:
- // just one fringe, delete this node and reinsert the fringe as leaf above
+ // The child is a compressed FringeNode. Prune the current node
+ // and re-insert the fringe as a leaf into the parent.
parent.DeleteChild(octet)
- // rebuild the prefix with octets, depth, ip version and addr
- // depth is the parent's depth, so add +1 here for the kid
- // lastOctet in cidrForFringe is the only addr (singleAddr)
+ // Reconstruct the full prefix for the fringe, as path compression
+ // requires the entire CIDR path, not just the remainder.
+ // depth is the parent's depth, so we offset by 1 for the kid's position.
fringePfx := CidrForFringe(octets, depth+1, is4, singleAddr)
- // ... (re)reinsert prefix/value at parents depth
parent.Insert(fringePfx, kid.Value, depth)
}
case pfxCount == 1:
- // just one prefix, delete this node and reinsert the idx as leaf above
+ // The node has exactly one prefix. Prune the node and elevate the
+ // prefix to the parent level as a leaf/fringe.
parent.DeleteChild(octet)
- // get prefix back from idx ...
- idx, _ := n.Prefixes.FirstSet() // single idx must be first bit set
+ // Retrieve the single prefix stored in this node.
+ idx, _ := n.Prefixes.FirstSet()
val := n.MustGetPrefix(idx)
- // ... and octet path
+ // Reconstruct the prefix from the path for re-insertion.
path := StridePath{}
copy(path[:], octets)
-
- // depth is the parent's depth, so add +1 here for the kid
pfx := CidrFromPath(path, depth+1, is4, idx)
- // ... (re)insert prefix/value at parents depth
parent.Insert(pfx, val, depth)
+ default:
+ panic("unreachable")
}
- // climb up the stack
+ // Move up to the next parent in the stack to continue pruning.
n = parent
}
}
-// Delete deletes the prefix and returns true if the prefix existed,
-// or false otherwise. The prefix must be in canonical form.
+// Delete removes the prefix from the trie rooted at n and returns true if the
+// prefix existed, false if it was not found. The prefix must be in canonical
+// (masked) form.
+//
+// The trie uses path compression, so a prefix may be stored in one of three ways:
+// - In the current node's prefix table when the prefix length aligns exactly
+// with the stride boundary at this depth (depth == strideCount).
+// - As a path-compressed FringeNode in a child slot for stride-aligned prefixes
+// (e.g. /8, /16, /24); occurs at depth == strideCount-1.
+// - As a path-compressed LeafNode in a child slot for prefixes otherwise.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
func (n *_NODE_TYPE[V]) Delete(pfx netip.Prefix) (exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
- ip := pfx.Addr()
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // record the nodes on the path to the deleted node, needed to purge
- // and/or path compress nodes after the deletion of a prefix
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
stack := [MaxTreeDepth]*_NODE_TYPE[V]{}
- // find the trie node
for depth, octet := range octets {
- depth = depth & DepthMask // BCE, Delete must be fast
+ depth &= DepthMask // BCE hint; keep Delete on the fast path
- // push current node on stack for path recording
- stack[depth] = n
+ stack[depth] = n // record current node before descending
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- // try to delete prefix in trie node
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
return true
}
+ // no child node exists at this octet; the prefix is not in the trie
if !n.Children.Test(octet) {
return false
}
+
+ // A child node exists at this octet path, retrieve it.
kid := n.MustGetChild(octet)
- // kid is node or leaf or fringe at octet
switch kid := kid.(type) {
case *_NODE_TYPE[V]:
- n = kid // descend down to next trie level
+ n = kid // descend to the next trie level
case *FringeNode[V]:
- // if pfx is no fringe at this depth, fast exit
- if !IsFringe(depth, pfx) {
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // pfx is fringe at depth, delete fringe
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Attention: pfx must be masked to be comparable!
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
return false
}
- // prefix is equal leaf, delete leaf
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
@@ -393,142 +421,150 @@ func (n *_NODE_TYPE[V]) Delete(pfx netip.Prefix) (exists bool) {
panic("unreachable")
}
-// DeletePersist is similar to delete but does not mutate the original trie.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *_NODE_TYPE[V]) DeletePersist(cloneFn value.CloneFunc[V], pfx netip.Prefix) (exists bool) {
- ip := pfx.Addr() // the pfx must be in canonical form
+// DeletePersist removes the prefix from the trie rooted at n using Copy-On-Write (COW) semantics.
+// It returns true if the prefix existed, false if it was not found. The prefix must be in
+// canonical (masked) form.
+//
+// Like [Delete], this method uses path compression. However, DeletePersist ensures
+// the structural integrity of the existing tree by cloning internal nodes along the
+// descent path (COW) before mutation.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
+func (n *_NODE_TYPE[V]) DeletePersist(cloneFn func(V) V, pfx netip.Prefix) (exists bool) {
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // Stack to keep track of cloned nodes along the path,
- // needed for purge and path compression after delete.
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
+ // Since this is a COW operation, we store the cloned nodes here.
stack := [MaxTreeDepth]*_NODE_TYPE[V]{}
- // Traverse the trie to locate the prefix to delete.
for depth, octet := range octets {
- // Keep track of the cloned node at current depth.
- stack[depth] = n
+ depth &= DepthMask // BCE hint; keep DeletePersist on the fast path
+ stack[depth] = n // record current node before descending
- if depth == lastOctetPlusOne {
- // Attempt to delete the prefix from the node's prefixes.
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
- // Prefix not found, nothing deleted.
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // After deletion, purge nodes and compress the path if needed.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
}
- addr := octet
-
- // If child node doesn't exist, no prefix to delete.
- if !n.Children.Test(addr) {
+ // no child node exists at this octet; the prefix is not in the trie
+ if !n.Children.Test(octet) {
return false
}
- // Fetch child node at current address.
- kid := n.MustGetChild(addr)
+ // A child node exists at this octet path, retrieve it to either continue
+ // our descent or perform a persistent delete on a compressed node.
+ kid := n.MustGetChild(octet)
switch kid := kid.(type) {
case *_NODE_TYPE[V]:
- // Clone the internal node for copy-on-write.
+ // Standard intermediate node: Clone the traversed path to maintain
+ // persistence (COW). We clone the child node before modifying it,
+ // then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // Replace child with cloned node.
- n.InsertChild(addr, kid)
-
- // Descend to cloned child node.
+ n.InsertChild(octet, kid)
n = kid
continue
case *FringeNode[V]:
- // Reached a path compressed fringe.
- if !IsFringe(depth, pfx) {
- // Prefix to delete not found here.
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // Delete the fringe node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Reached a path compressed leaf node.
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
- // Leaf prefix does not match; nothing to delete.
return false
}
- // Delete leaf node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
- // Unexpected node type indicates a logic error.
panic("logic error, wrong node type")
}
}
- // Should never happen: traversal always returns or panics inside loop.
panic("unreachable")
}
// Get retrieves the value associated with the given network prefix.
-// Returns the stored value and true if the prefix exists in this node,
-// zero value and false if the prefix is not found.
+// Traversal descends through the trie using the prefix's octets.
+//
+// The lookup handles path compression transparently:
+// - If the path matches an internal node at the target stride, the value is retrieved
+// from the node's prefix table.
+// - If the path leads to a compressed LeafNode or FringeNode, the function verifies
+// the prefix match before returning the value.
//
// Parameters:
-// - pfx: The network prefix to look up (must be in canonical form)
+// - pfx: The network prefix to look up (must be in canonical form).
//
// Returns:
-// - val: The value associated with the prefix (zero value if not found)
-// - exists: True if the prefix was found, false otherwise
+// - val: The value associated with the prefix (zero value if not found).
+// - exists: True if the prefix was found, false otherwise.
func (n *_NODE_TYPE[V]) Get(pfx netip.Prefix) (val V, exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
+ // The prefix must be provided in canonical (masked) form for correct trie traversal.
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the trie node
+ // Traverse the trie octet by octet based on the prefix path.
for depth, octet := range octets {
- if depth == lastOctetPlusOne {
- return n.GetPrefix(art.PfxToIdx(octet, lastBits))
+ // At the target stride boundary, the prefix is expected in this node's
+ // prefix table.
+ if depth == strideCount {
+ return n.GetPrefix(art.PfxToIdx(octet, modBits))
}
+ // If no child exists at this path, the prefix is not in the trie.
kidAny, ok := n.GetChild(octet)
if !ok {
return val, false
}
- // kid is node or leaf or fringe at octet
+ // Identify the node type at this path segment.
switch kid := kidAny.(type) {
case *_NODE_TYPE[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next level.
+ n = kid
case *FringeNode[V]:
- // reached a path compressed fringe, stop traversing
- if IsFringe(depth, pfx) {
+ // Reached a path-compressed FringeNode.
+ // Verify if the prefix qualifies as a fringe at this depth to return a match.
+ if IsFringe(depth, pfxLen) {
return kid.Value, true
}
return val, false
case *LeafNode[V]:
- // reached a path compressed prefix, stop traversing
+ // Reached a path-compressed LeafNode.
+ // Check if the stored prefix matches the lookup prefix exactly.
if kid.Prefix == pfx {
return kid.Value, true
}
@@ -546,7 +582,7 @@ func (n *_NODE_TYPE[V]) Get(pfx netip.Prefix) (val V, exists bool) {
// The callback receives the current value (if found) and existence flag, and returns
// a new value and deletion flag.
//
-// modify returns the size delta (-1, 0, +1).
+// Modify returns the size delta (-1, 0, +1).
// This method handles path traversal, node creation for new paths, and automatic
// purge/compress operations after deletions.
//
@@ -560,9 +596,10 @@ func (n *_NODE_TYPE[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V
var zero V
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// record the nodes on the path to the deleted node, needed to purge
// and/or path compress nodes after the deletion of a prefix
@@ -570,16 +607,15 @@ func (n *_NODE_TYPE[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V
// find the proper trie node to update prefix
for depth, octet := range octets {
- depth = depth & DepthMask // BCE
+ depth &= DepthMask // BCE
// push current node on stack for path recording
stack[depth] = n
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // stride for this prefix. Insert or update it directly in this node's prefix table.
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
oldVal, existed := n.GetPrefix(idx)
newVal, del := cb(oldVal, existed)
@@ -619,7 +655,7 @@ func (n *_NODE_TYPE[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V
}
// insert
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
n.InsertChild(octet, NewFringeNode(newVal))
} else {
n.InsertChild(octet, NewLeafNode(pfx, newVal))
@@ -678,7 +714,7 @@ func (n *_NODE_TYPE[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V
case *FringeNode[V]:
// update existing value if prefix is fringe
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
newVal, del := cb(kid.Value, true)
if !del {
kid.Value = newVal
@@ -808,8 +844,8 @@ func (n *_NODE_TYPE[V]) EqualRec(o *_NODE_TYPE[V]) bool {
//
// It returns immediately if n is nil or empty. For each visited internal node
// it calls dump to write the node's representation, then iterates its child
-// addresses and recurses into children that implement nodeDumper[V] (internal
-// subnodes). The path slice and depth together represent the byte-wise path
+// addresses and recurses into children of type *_NODE_TYPE[V] (internal subnodes).
+// The path slice and depth together represent the byte-wise path
// from the root to the current node; depth is incremented for each recursion.
// The is4 flag controls IPv4/IPv6 formatting used by dump.
func (n *_NODE_TYPE[V]) DumpRec(w io.Writer, path StridePath, depth int, is4 bool) {
@@ -837,8 +873,8 @@ func (n *_NODE_TYPE[V]) dump(w io.Writer, path StridePath, depth int, is4 bool)
bits := depth * strideLen
indent := strings.Repeat(".", depth)
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// node type with depth and octet path and bits.
fmt.Fprintf(w, "\n%s[%s] depth: %d path: [%s] / %d\n",
@@ -1001,7 +1037,7 @@ func (n *_NODE_TYPE[V]) DumpString(octets []uint8, depth int, is4 bool) string {
// - stopNode: has children but no subnodes (nodes == 0)
// - halfNode: contains at least one leaf or fringe and also has subnodes, but
// no prefixes
-// - fullNode: has prefixes or leaves/fringes and also has subnodes
+// - fullNode: has prefixes and also has subnodes
// - pathNode: has subnodes only (no prefixes, leaves, or fringes)
//
// The order of these checks is significant to ensure the correct classification.
@@ -1058,7 +1094,7 @@ func (n *_NODE_TYPE[V]) Stats() (s StatsT) {
// It walks the node tree recursively and sums immediate counts (prefixes and
// child slots) plus the number of nodes, leaves, and fringe nodes in the
// subtree. If n is nil or empty, a zeroed stats is returned. The returned
-// stats.nodes includes the current node. The function will panic if a child
+// SubNodes count includes the current node. The function will panic if a child
// has an unexpected concrete type.
func (n *_NODE_TYPE[V]) StatsRec() (s StatsT) {
if n == nil || n.IsEmpty() {
@@ -1114,8 +1150,8 @@ func (n *_NODE_TYPE[V]) FprintRec(w io.Writer, parent TrieItem[V], pad string) e
return CmpPrefix(a.Cidr, b.Cidr)
})
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// for all direct item under this node ...
for i, item := range directItems {
@@ -1212,7 +1248,7 @@ func (n *_NODE_TYPE[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth i
path[depth] = addr
directItems = append(directItems, kid.DirectItemsRec(0, path, depth+1, is4)...)
- case *LeafNode[V]: // path-compressed child, stop's recursion for this child
+ case *LeafNode[V]: // path-compressed child, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1221,7 +1257,7 @@ func (n *_NODE_TYPE[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth i
}
directItems = append(directItems, item)
- case *FringeNode[V]: // path-compressed fringe, stop's recursion for this child
+ case *FringeNode[V]: // path-compressed fringe, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1255,9 +1291,9 @@ func (n *_NODE_TYPE[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth i
// The merge operation is destructive on the receiver n, but leaves the source node o unchanged.
//
// Returns the number of duplicate prefixes that were overwritten during merging.
-func (n *_NODE_TYPE[V]) UnionRec(cloneFn value.CloneFunc[V], o *_NODE_TYPE[V], depth int) (duplicates int) {
+func (n *_NODE_TYPE[V]) UnionRec(cloneFn func(V) V, o *_NODE_TYPE[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1288,9 +1324,9 @@ func (n *_NODE_TYPE[V]) UnionRec(cloneFn value.CloneFunc[V], o *_NODE_TYPE[V], d
}
// UnionRecPersist is similar to unionRec but performs an immutable union of nodes.
-func (n *_NODE_TYPE[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *_NODE_TYPE[V], depth int) (duplicates int) {
+func (n *_NODE_TYPE[V]) UnionRecPersist(cloneFn func(V) V, o *_NODE_TYPE[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1339,7 +1375,7 @@ func (n *_NODE_TYPE[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *_NODE_TYP
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *_NODE_TYPE[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *_NODE_TYPE[V]) handleMatrix(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*_NODE_TYPE[V])
@@ -1456,7 +1492,7 @@ func (n *_NODE_TYPE[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *_NODE_TYPE[V]) handleMatrixPersist(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *_NODE_TYPE[V]) handleMatrixPersist(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*_NODE_TYPE[V])
@@ -1688,9 +1724,7 @@ func (n *_NODE_TYPE[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, childAddr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1725,9 +1759,7 @@ func (n *_NODE_TYPE[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, addr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1913,9 +1945,10 @@ func (n *_NODE_TYPE[V]) EachSubnet(octets []byte, depth int, is4 bool, pfxIdx ui
// the iteration early.
func (n *_NODE_TYPE[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// stack of the traversed nodes for reverse ordering of supernets
stack := [MaxTreeDepth]*_NODE_TYPE[V]{}
@@ -1928,7 +1961,7 @@ func (n *_NODE_TYPE[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V)
LOOP:
for depth, octet = range octets {
// stepped one past the last stride of interest; back up to last and exit
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
depth--
break
}
@@ -1989,11 +2022,10 @@ LOOP:
// all others are just host routes
var idx uint8
octet = octets[depth]
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx = art.PfxToIdx(octet, lastBits)
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
+ if depth == strideCount {
+ idx = art.PfxToIdx(octet, modBits)
} else {
idx = art.OctetToIdx(octet)
}
@@ -2030,17 +2062,18 @@ LOOP:
func (n *_NODE_TYPE[V]) Subnets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
// values derived from pfx
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// find the trie node
for depth, octet := range octets {
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
// so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
n.EachSubnet(octets, depth, is4, idx, yield)
return
}
@@ -2158,7 +2191,7 @@ func (n *_NODE_TYPE[V]) Overlaps(o *_NODE_TYPE[V], depth int) bool {
// OverlapsRoutes compares the prefix sets of two nodes (n and o).
//
// It first checks for direct bitset intersection (identical indices),
-// then walks both prefix sets using lpmTest to detect if any
+// then walks both prefix sets using the Contains method to detect if any
// of the n-prefixes is contained in o, or vice versa.
func (n *_NODE_TYPE[V]) OverlapsRoutes(o *_NODE_TYPE[V]) bool {
// some prefixes are identical, trivial overlap
@@ -2301,19 +2334,20 @@ func (n *_NODE_TYPE[V]) OverlapsSameChildren(o *_NODE_TYPE[V], depth int) bool {
// trie traversal across varying prefix lengths and compression levels.
func (n *_NODE_TYPE[V]) OverlapsPrefixAtDepth(pfx netip.Prefix, depth int) bool {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
for ; depth < len(octets); depth++ {
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
break
}
octet := octets[depth]
// full octet path in node trie, check overlap with last prefix octet
- if depth == lastOctetPlusOne {
- return n.OverlapsIdx(art.PfxToIdx(octet, lastBits))
+ if depth == strideCount {
+ return n.OverlapsIdx(art.PfxToIdx(octet, modBits))
}
// test if any route overlaps prefix´ so far
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/commontests_tmpl.go b/vendor/github.com/gaissmai/bart/internal/nodes/commontests_tmpl.go
index fd2262cba4..d600ebcdf8 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/commontests_tmpl.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/commontests_tmpl.go
@@ -1,6 +1,6 @@
//go:build generate
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
//go:generate ../../scripts/generate-node-tests.sh
@@ -35,8 +35,8 @@ func (n *_NODE_TYPE[V]) DumpRec(io.Writer, StridePath, int, bool)
func (n *_NODE_TYPE[V]) FprintRec(io.Writer, TrieItem[V], string) (_ error) { return }
func (n *_NODE_TYPE[V]) Insert(netip.Prefix, V, int) (_ bool) { return }
func (n *_NODE_TYPE[V]) Delete(netip.Prefix) (_ bool) { return }
-func (n *_NODE_TYPE[V]) InsertPersist(value.CloneFunc[V], netip.Prefix, V, int) (_ bool) { return }
-func (n *_NODE_TYPE[V]) DeletePersist(value.CloneFunc[V], netip.Prefix) (_ bool) { return }
+func (n *_NODE_TYPE[V]) InsertPersist(func(V) V, netip.Prefix, V, int) (_ bool) { return }
+func (n *_NODE_TYPE[V]) DeletePersist(func(V) V, netip.Prefix) (_ bool) { return }
func (n *_NODE_TYPE[V]) Subnets(netip.Prefix, func(netip.Prefix, V) bool) { return }
func (n *_NODE_TYPE[V]) Supernets(netip.Prefix, func(netip.Prefix, V) bool) { return }
func (n *_NODE_TYPE[V]) AllRec(StridePath, int, bool, func(netip.Prefix, V) bool) (_ bool) { return }
@@ -766,3 +766,501 @@ func TestFprintRec_NonZST__NODE_TYPE(t *testing.T) {
t.Errorf("Expected prefix and value 'testval' in output, but got:\n%s", output)
}
}
+
+// TestEqualRec__NODE_TYPE tests the recursive node equality comparison.
+func TestEqualRec__NODE_TYPE(t *testing.T) {
+ t.Parallel()
+
+ // nil checks
+ var nilNode1, nilNode2 *_NODE_TYPE[int]
+ if !nilNode1.EqualRec(nilNode2) {
+ t.Error("nil nodes should be equal")
+ }
+
+ n1 := new(_NODE_TYPE[int])
+ if n1.EqualRec(nilNode1) {
+ t.Error("non-nil node should not be equal to nil")
+ }
+ if nilNode1.EqualRec(n1) {
+ t.Error("nil node should not be equal to non-nil")
+ }
+
+ // identical nodes
+ if !n1.EqualRec(n1) {
+ t.Error("node should be equal to itself")
+ }
+
+ // different prefix bitsets
+ n2 := new(_NODE_TYPE[int])
+ n1.Insert(mpp("10.0.0.0/7"), 42, 0)
+ if n1.EqualRec(n2) {
+ t.Error("nodes with different prefixes should not be equal")
+ }
+
+ // different values
+ // Skip for LiteNode because it has no real payload values
+ if _, isLite := any(n1).(*LiteNode[int]); !isLite {
+ n2.Insert(mpp("10.0.0.0/7"), 43, 0)
+ if n1.EqualRec(n2) {
+ t.Error("nodes with same prefixes but different values should not be equal")
+ }
+ }
+
+ // same prefix and value
+ n2_same := new(_NODE_TYPE[int])
+ n2_same.Insert(mpp("10.0.0.0/7"), 42, 0)
+ if _, isLite := any(n1).(*LiteNode[int]); !isLite {
+ if !n1.EqualRec(n2_same) {
+ t.Error("nodes with same prefixes and values should be equal")
+ }
+ }
+
+ // different children bitsets
+ n3 := new(_NODE_TYPE[int])
+ n4 := new(_NODE_TYPE[int])
+ n3.Insert(mpp("10.0.0.0/8"), 42, 0) // this is a fringe node at depth 1, and inserts into Children
+ if n3.EqualRec(n4) {
+ t.Error("nodes with different children should not be equal")
+ }
+
+ // fringe nodes with different values
+ if _, isLite := any(n3).(*LiteNode[int]); !isLite {
+ n4.Insert(mpp("10.0.0.0/8"), 43, 0)
+ if n3.EqualRec(n4) {
+ t.Error("nodes with different fringe values should not be equal")
+ }
+ }
+
+ // leaf nodes with different prefixes/values
+ n5 := new(_NODE_TYPE[int])
+ n6 := new(_NODE_TYPE[int])
+ n5.Insert(mpp("10.20.0.0/15"), 42, 0) // leaf node at depth 1
+ n6.Insert(mpp("10.30.0.0/15"), 42, 0) // different leaf node prefix
+ if n5.EqualRec(n6) {
+ t.Error("nodes with different leaf prefixes should not be equal")
+ }
+
+ if _, isLite := any(n5).(*LiteNode[int]); !isLite {
+ n7 := new(_NODE_TYPE[int])
+ n7.Insert(mpp("10.20.0.0/15"), 43, 0) // different leaf value
+ if n5.EqualRec(n7) {
+ t.Error("nodes with different leaf values should not be equal")
+ }
+ }
+}
+
+// TestOverlapsExtra__NODE_TYPE tests specific edge cases in trie overlap detection.
+func TestOverlapsExtra__NODE_TYPE(t *testing.T) {
+ t.Parallel()
+
+ // 1. Test OverlapsSameChildren loop continuation & completion (returning false)
+ t.Run("same_children_no_overlap", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n2 := new(_NODE_TYPE[int])
+
+ // Insert disjoint child subnets at address 10 and 20
+ n1.Insert(mpp("10.10.1.0/24"), 42, 0)
+ n1.Insert(mpp("10.20.1.0/24"), 42, 0)
+
+ n2.Insert(mpp("10.10.2.0/24"), 42, 0)
+ n2.Insert(mpp("10.20.2.0/24"), 42, 0)
+
+ if n1.Overlaps(n2, 0) {
+ t.Error("expected no overlap between disjoint child subnets")
+ }
+ })
+
+ // 2. Test OverlapsSameChildren loop continuation & early exit (returning true)
+ t.Run("same_children_first_no_overlap_second_overlap", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n2 := new(_NODE_TYPE[int])
+
+ // Address 10 does not overlap, address 20 does overlap
+ n1.Insert(mpp("10.10.1.0/24"), 42, 0)
+ n1.Insert(mpp("10.20.1.0/24"), 42, 0)
+
+ n2.Insert(mpp("10.10.2.0/24"), 42, 0)
+ n2.Insert(mpp("10.20.1.0/24"), 42, 0) // overlap here
+
+ if !n1.Overlaps(n2, 0) {
+ t.Error("expected overlap since second child subnet overlaps")
+ }
+ })
+
+ // 3. Test OverlapsSameChildren with matching child at address 255 that does not overlap
+ t.Run("same_children_boundary_255_no_overlap", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n2 := new(_NODE_TYPE[int])
+
+ n1.Insert(mpp("10.255.1.0/24"), 42, 0)
+ n2.Insert(mpp("10.255.2.0/24"), 42, 0)
+
+ if n1.Overlaps(n2, 0) {
+ t.Error("expected no overlap on boundary 255")
+ }
+ })
+
+ // 4. Test OverlapsPrefixAtDepth with LeafNode and FringeNode
+ t.Run("prefix_overlaps_leaf_node_true", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n1.Insert(mpp("10.20.0.0/15"), 42, 0)
+
+ if !n1.OverlapsPrefixAtDepth(mpp("10.20.0.0/16"), 0) {
+ t.Error("expected overlap with leaf node prefix")
+ }
+ })
+
+ t.Run("prefix_overlaps_leaf_node_false", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n1.Insert(mpp("10.20.0.0/15"), 42, 0)
+
+ if n1.OverlapsPrefixAtDepth(mpp("10.30.0.0/16"), 0) {
+ t.Error("expected no overlap with disjoint prefix")
+ }
+ })
+
+ t.Run("prefix_overlaps_fringe_node", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n1.Insert(mpp("10.0.0.0/8"), 42, 0)
+
+ if !n1.OverlapsPrefixAtDepth(mpp("10.0.0.0/16"), 0) {
+ t.Error("expected overlap with fringe node")
+ }
+ })
+
+ // 5. Test OverlapsPrefixAtDepth with deeper path walk
+ t.Run("prefix_overlaps_idx_at_last_octet", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n1.Insert(mpp("10.20.30.0/24"), 42, 0)
+
+ if !n1.OverlapsPrefixAtDepth(mpp("10.20.0.0/16"), 0) {
+ t.Error("expected overlap at last octet")
+ }
+ })
+
+ t.Run("prefix_overlaps_contains_at_depth", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n1.Insert(mpp("10.128.30.0/24"), 42, 0)
+ n1.Insert(mpp("10.128.0.0/9"), 42, 0)
+
+ if !n1.OverlapsPrefixAtDepth(mpp("10.128.30.0/24"), 0) {
+ t.Error("expected overlap with contains check at depth 1")
+ }
+ })
+}
+
+// TestDumpStringExtra__NODE_TYPE tests type classification in DumpString and DumpRec.
+func TestDumpStringExtra__NODE_TYPE(t *testing.T) {
+ t.Parallel()
+
+ // 1. Create a halfNode at the root
+ n1 := new(_NODE_TYPE[int])
+ // LeafNode under child slot 10:
+ n1.Insert(mpp("10.20.0.0/15"), 42, 0)
+ // Internal node under child slot 11 (requires branching to prevent path compression):
+ n1.Insert(mpp("11.30.40.0/24"), 42, 0)
+ n1.Insert(mpp("11.30.50.0/24"), 42, 0)
+
+ dump1 := n1.DumpString(nil, 0, true)
+ if !strings.Contains(dump1, "HALF") {
+ t.Errorf("expected HALF node type in dump, got:\n%s", dump1)
+ }
+
+ // 2. Create a pathNode at the root
+ n2 := new(_NODE_TYPE[int])
+ // Branching paths under child slot 10 to create an internal node at root child 10
+ n2.Insert(mpp("10.20.30.0/24"), 42, 0)
+ n2.Insert(mpp("10.20.40.0/24"), 42, 0)
+
+ dump2 := n2.DumpString(nil, 0, true)
+ if !strings.Contains(dump2, "PATH") {
+ t.Errorf("expected PATH node type in dump, got:\n%s", dump2)
+ }
+
+ // 3. Test DumpRec on nil/empty node
+ var nilNode *_NODE_TYPE[int]
+ var buf bytes.Buffer
+ nilNode.DumpRec(&buf, StridePath{}, 0, true)
+ if buf.Len() != 0 {
+ t.Error("expected empty buffer for nil DumpRec")
+ }
+
+ buf.Reset()
+ emptyNode := new(_NODE_TYPE[int])
+ emptyNode.DumpRec(&buf, StridePath{}, 0, true)
+ if buf.Len() != 0 {
+ t.Error("expected empty buffer for empty DumpRec")
+ }
+}
+
+// TestDeletePurgeExtra__NODE_TYPE tests the bottom-up trie compression on delete.
+func TestDeletePurgeExtra__NODE_TYPE(t *testing.T) {
+ t.Parallel()
+
+ // 1. Trigger PurgeAndCompress: case childCount == 1 with LeafNode
+ t.Run("purge_leaf_node", func(t *testing.T) {
+ t.Parallel()
+ n := new(_NODE_TYPE[int])
+ n.Insert(mpp("10.20.10.0/24"), 42, 0)
+ n.Insert(mpp("10.20.20.0/24"), 42, 0)
+
+ n.Delete(mpp("10.20.20.0/24"))
+
+ if _, ok := n.Get(mpp("10.20.10.0/24")); !ok {
+ t.Error("expected remaining leaf node to be present")
+ }
+ })
+
+ // 2. Trigger PurgeAndCompress: case childCount == 1 with FringeNode
+ t.Run("purge_fringe_node", func(t *testing.T) {
+ t.Parallel()
+ n := new(_NODE_TYPE[int])
+ n.Insert(mpp("10.20.0.0/16"), 42, 0)
+ n.Insert(mpp("10.30.0.0/16"), 42, 0)
+
+ n.Delete(mpp("10.30.0.0/16"))
+
+ if _, ok := n.Get(mpp("10.20.0.0/16")); !ok {
+ t.Error("expected remaining fringe node to be present")
+ }
+ })
+
+ // 3. Trigger PurgeAndCompress: case pfxCount == 1
+ t.Run("purge_single_prefix", func(t *testing.T) {
+ t.Parallel()
+ n := new(_NODE_TYPE[int])
+ n.Insert(mpp("10.20.0.0/16"), 42, 0)
+ n.Insert(mpp("10.0.0.0/8"), 42, 0)
+
+ n.Delete(mpp("10.20.0.0/16"))
+
+ if _, ok := n.Get(mpp("10.0.0.0/8")); !ok {
+ t.Error("expected remaining prefix to be present")
+ }
+ })
+}
+
+// TestUnionRecExtra__NODE_TYPE tests specific edge cases in trie Union operations.
+func TestUnionRecExtra__NODE_TYPE(t *testing.T) {
+ t.Parallel()
+
+ _, isLite := any(new(_NODE_TYPE[int])).(*LiteNode[int])
+
+ // 1. Cover handleMatrix case 2: thisIsNode && otherIsLeaf, where leaf already exists in thisNode
+ t.Run("node_leaf_exists", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n2 := new(_NODE_TYPE[int])
+
+ // Both n1 and n2 have child at octet 10, but:
+ // n1's child is an internal node (requires branching to prevent path compression)
+ n1.Insert(mpp("10.10.10.0/24"), 42, 0)
+ n1.Insert(mpp("10.10.20.0/24"), 42, 0)
+
+ // n2's child is a LeafNode with "10.10.20.0/24"
+ n2.Insert(mpp("10.10.20.0/24"), 43, 0)
+
+ n1.UnionRec(value.CloneFnFactory[int](), n2, 0)
+
+ val, ok := n1.Get(mpp("10.10.20.0/24"))
+ if !ok {
+ t.Fatal("expected prefix to exist")
+ }
+ if !isLite && val != 43 {
+ t.Errorf("expected value 43, got %v", val)
+ }
+ })
+
+ // 2. Cover handleMatrix case 2: thisIsNode && otherIsFringe, where fringe already exists in thisNode
+ t.Run("node_fringe_exists", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n2 := new(_NODE_TYPE[int])
+
+ // Both n1 and n2 have child at octet 10.
+ // n1's child is an internal node and contains the default route/fringe "10.0.0.0/8"
+ n1.Insert(mpp("10.10.10.0/24"), 42, 0)
+ n1.Insert(mpp("10.0.0.0/8"), 42, 0)
+
+ // n2's child is a FringeNode "10.0.0.0/8"
+ n2.Insert(mpp("10.0.0.0/8"), 43, 0)
+
+ n1.UnionRec(value.CloneFnFactory[int](), n2, 0)
+
+ val, ok := n1.Get(mpp("10.0.0.0/8"))
+ if !ok {
+ t.Fatal("expected prefix to exist")
+ }
+ if !isLite && val != 43 {
+ t.Errorf("expected value 43, got %v", val)
+ }
+ })
+
+ // 3. Cover handleMatrixPersist case 2 counterpart
+ t.Run("node_leaf_exists_persist", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n2 := new(_NODE_TYPE[int])
+
+ n1.Insert(mpp("10.10.10.0/24"), 42, 0)
+ n1.Insert(mpp("10.10.20.0/24"), 42, 0)
+
+ n2.Insert(mpp("10.10.20.0/24"), 43, 0)
+
+ n1.UnionRecPersist(value.CloneFnFactory[int](), n2, 0)
+
+ val, ok := n1.Get(mpp("10.10.20.0/24"))
+ if !ok {
+ t.Fatal("expected prefix to exist")
+ }
+ if !isLite && val != 43 {
+ t.Errorf("expected value 43, got %v", val)
+ }
+ })
+
+ t.Run("node_fringe_exists_persist", func(t *testing.T) {
+ t.Parallel()
+ n1 := new(_NODE_TYPE[int])
+ n2 := new(_NODE_TYPE[int])
+
+ n1.Insert(mpp("10.10.10.0/24"), 42, 0)
+ n1.Insert(mpp("10.0.0.0/8"), 42, 0)
+
+ n2.Insert(mpp("10.0.0.0/8"), 43, 0)
+
+ n1.UnionRecPersist(value.CloneFnFactory[int](), n2, 0)
+
+ val, ok := n1.Get(mpp("10.0.0.0/8"))
+ if !ok {
+ t.Fatal("expected prefix to exist")
+ }
+ if !isLite && val != 43 {
+ t.Errorf("expected value 43, got %v", val)
+ }
+ })
+}
+
+// TestSubnetsEarlyExit__NODE_TYPE tests early termination in Subnets traversal.
+func TestSubnetsEarlyExit__NODE_TYPE(t *testing.T) {
+ t.Parallel()
+
+ n := new(_NODE_TYPE[int])
+ n.Insert(mpp("10.0.0.0/8"), 1, 0)
+ n.Insert(mpp("10.10.10.0/24"), 2, 0)
+ n.Insert(mpp("10.10.20.0/24"), 3, 0)
+ n.Insert(mpp("10.20.0.0/15"), 4, 0)
+
+ // Traversal 1: yield returns false immediately
+ yieldCount := 0
+ n.Subnets(mpp("10.0.0.0/8"), func(pfx netip.Prefix, val int) bool {
+ yieldCount++
+ return false // stop immediately
+ })
+
+ if yieldCount != 1 {
+ t.Errorf("expected yieldCount to be 1, got %d", yieldCount)
+ }
+
+ // Traversal 2: yield returns false after 2 items
+ yieldCount = 0
+ n.Subnets(mpp("10.0.0.0/8"), func(pfx netip.Prefix, val int) bool {
+ yieldCount++
+ if yieldCount == 2 {
+ return false
+ }
+ return true
+ })
+
+ if yieldCount != 2 {
+ t.Errorf("expected yieldCount to be 2, got %d", yieldCount)
+ }
+}
+
+// TestSupernetsExtra__NODE_TYPE tests specific edge cases and early exits in Supernets traversal.
+func TestSupernetsExtra__NODE_TYPE(t *testing.T) {
+ t.Parallel()
+
+ n := new(_NODE_TYPE[int])
+ // LeafNode at depth 1:
+ n.Insert(mpp("10.20.0.0/15"), 1, 0)
+ // FringeNode at depth 1:
+ n.Insert(mpp("10.30.0.0/16"), 2, 0)
+ // Normal prefixes:
+ n.Insert(mpp("10.0.0.0/8"), 3, 0)
+ n.Insert(mpp("10.40.50.0/24"), 4, 0)
+
+ // 1. LeafNode longer prefix check
+ yielded := []netip.Prefix{}
+ n.Supernets(mpp("10.20.0.0/15"), func(pfx netip.Prefix, val int) bool {
+ yielded = append(yielded, pfx)
+ return true
+ })
+ if len(yielded) != 2 {
+ t.Errorf("expected 2 supernets, got %v", yielded)
+ }
+
+ // 2. FringeNode longer prefix check
+ yielded = []netip.Prefix{}
+ n.Supernets(mpp("10.30.0.0/16"), func(pfx netip.Prefix, val int) bool {
+ yielded = append(yielded, pfx)
+ return true
+ })
+ if len(yielded) != 2 {
+ t.Errorf("expected 2 supernets, got %v", yielded)
+ }
+
+ // 3. Early exits on yield
+ // LeafNode yield false
+ yieldCount := 0
+ n.Supernets(mpp("10.20.0.0/15"), func(pfx netip.Prefix, val int) bool {
+ yieldCount++
+ if pfx == mpp("10.20.0.0/15") {
+ return false
+ }
+ return true
+ })
+ if yieldCount != 1 {
+ t.Errorf("expected yieldCount 1 on leaf early exit, got %d", yieldCount)
+ }
+
+ // FringeNode yield false
+ yieldCount = 0
+ n.Supernets(mpp("10.30.0.0/16"), func(pfx netip.Prefix, val int) bool {
+ yieldCount++
+ if pfx == mpp("10.30.0.0/16") {
+ return false
+ }
+ return true
+ })
+ if yieldCount != 1 {
+ t.Errorf("expected yieldCount 1 on fringe early exit, got %d", yieldCount)
+ }
+
+ // Backtracking yield false
+ yieldCount = 0
+ n.Supernets(mpp("10.40.50.0/24"), func(pfx netip.Prefix, val int) bool {
+ yieldCount++
+ return false
+ })
+ if yieldCount != 1 {
+ t.Errorf("expected yieldCount 1 on backtracking early exit, got %d", yieldCount)
+ }
+
+ // 4. Trigger depth > strideCount
+ yielded = []netip.Prefix{}
+ n.Supernets(mpp("10.40.0.0/16"), func(pfx netip.Prefix, val int) bool {
+ yielded = append(yielded, pfx)
+ return true
+ })
+ if len(yielded) != 1 || yielded[0] != mpp("10.0.0.0/8") {
+ t.Errorf("expected only 10.0.0.0/8, got %v", yielded)
+ }
+}
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/fast.go b/vendor/github.com/gaissmai/bart/internal/nodes/fast.go
index 2248fc8ecf..fdc5185c3b 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/fast.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/fast.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package nodes
@@ -6,236 +6,173 @@ package nodes
import (
"iter"
- "github.com/gaissmai/bart/internal/bitset"
"github.com/gaissmai/bart/internal/lpm"
- "github.com/gaissmai/bart/internal/value"
+ "github.com/gaissmai/bart/internal/sparse"
)
-// FastNode is a trie level node in the multibit routing table.
-//
-// Each FastNode contains two sections (Prefixes and Children), each with
-// a BitSet256 tracking occupied indices and a fixed-size Items array:
-// - Prefixes.BitSet256: tracks which prefix indices are occupied.
-// - Prefixes.Items: [256]*V storing routing entry values.
-// - Children.BitSet256: tracks which child indices are occupied.
-// - Children.Items: [256]*any holding subtries or path-compressed leaves/fringes
-// (branching factor 256, 8 bits per stride).
-// - PfxCount: cached count of active prefixes (avoids BitSet.Size() calls).
-// - CldCount: cached count of child nodes (avoids BitSet.Size() calls).
-//
-// Prefixes use a complete binary tree layout driven by the baseIndex() function
-// from the ART algorithm for fast LPM lookup.
-//
-// Entries in Children.Items (each *any containing a pointer) may be:
-// - **FastNode[V] -> internal child node for further traversal
-// - **LeafNode[V] -> path-comp. node (depth < maxDepth - 1)
-// - **FringeNode[V] -> path-comp. node (depth == maxDepth - 1, stride-aligned)
-//
-// Note: Children.Items uses *any (pointer to any) instead of any to reduce memory by
-// ~30%, since many slots are nil and *any takes 1 word vs 2 words for nil any.
+// FastNode is based on [BartNode], but it also uses a cache ([256]uint8)
+// per node to speed up traversal of the multi-bit trie.
+// Lookups become faster, but this requires more memory per prefix,
+// and updates (insertions/deletions) also become slower due to the
+// overhead of managing the cache.
type FastNode[V any] struct {
- // Prefixes holding prefix -> value pointers, organized as a CBT
- // for fast LPM lookup within the node.
- Prefixes struct {
- bitset.BitSet256
- Items [256]*V
- }
+ Prefixes sparse.Array256[V]
+ Children sparse.Array256[any]
+ // map addr to slice idx (aka rank)
+ childRankCache [256]uint8
+}
- // Children holding subtries or path-compressed leaves or fringes.
- Children struct {
- bitset.BitSet256
- Items [256]*any // pointer to any, see explanation above
+// IsEmpty returns true if the node contains no routing entries (prefixes)
+// and no child nodes. Empty nodes are candidates for compression or removal
+// during trie optimization.
+func (n *FastNode[V]) IsEmpty() bool {
+ if n == nil {
+ return true
}
-
- // PfxCount replaces expensive BitSet256.Size() calls. Automatically
- // maintained during InsertPrefix() and DeletePrefix() operations.
- PfxCount uint16
-
- // CldCount replaces expensive BitSet.Size() calls. Automatically
- // maintained during InsertChild() and DeleteChild() operations.
- CldCount uint16
+ return n.Prefixes.Len() == 0 && n.Children.Len() == 0
}
// PrefixCount returns the number of prefixes stored in this node.
func (n *FastNode[V]) PrefixCount() int {
- return int(n.PfxCount)
+ return n.Prefixes.Len()
}
// ChildCount returns the number of slots used in this node.
func (n *FastNode[V]) ChildCount() int {
- return int(n.CldCount)
+ return n.Children.Len()
}
-// IsEmpty returns true if node has neither prefixes nor children
-func (n *FastNode[V]) IsEmpty() bool {
- if n == nil {
- return true
- }
- return n.PfxCount == 0 && n.CldCount == 0
+// InsertPrefix adds or updates a routing entry at the specified index with the given value.
+// It returns true if a prefix already existed at that index (indicating an update),
+// false if this is a new insertion.
+func (n *FastNode[V]) InsertPrefix(idx uint8, val V) (exists bool) {
+ _, exists = n.Prefixes.InsertAt(idx, val)
+ return
}
-// GetChild returns the child node at the specified address and true if it exists.
-// If no child exists at addr, returns nil and false.
-func (n *FastNode[V]) GetChild(addr uint8) (any, bool) {
- if anyPtr := n.Children.Items[addr]; anyPtr != nil {
- return *anyPtr, true
- }
- return nil, false
+// GetPrefix retrieves the value associated with the prefix at the given index.
+// Returns the value and true if found, or zero value and false if not present.
+func (n *FastNode[V]) GetPrefix(idx uint8) (val V, exists bool) {
+ return n.Prefixes.Get(idx)
}
-// MustGetChild returns the child node at the specified address.
-// Panics if no child exists at addr. This method should only be called
-// when the caller has verified the child exists.
-func (n *FastNode[V]) MustGetChild(addr uint8) any {
- // panics if n.children[addr] is nil
- return *n.Children.Items[addr]
+// MustGetPrefix retrieves the value at the specified index, panicking if not found.
+// This method should only be used when the caller is certain the index exists.
+func (n *FastNode[V]) MustGetPrefix(idx uint8) (val V) {
+ return n.Prefixes.MustGet(idx)
}
-// AllChildren returns an iterator over all child nodes.
-// Each iteration yields the child's address (uint8) and the child node (any).
-func (n *FastNode[V]) AllChildren() iter.Seq2[uint8, any] {
- return func(yield func(addr uint8, child any) bool) {
+// AllIndices returns an iterator over all prefix entries.
+// Each iteration yields the prefix index (uint8) and its associated value (V).
+func (n *FastNode[V]) AllIndices() iter.Seq2[uint8, V] {
+ return func(yield func(uint8, V) bool) {
var buf [256]uint8
- for _, addr := range n.Children.AsSlice(&buf) {
- child := *n.Children.Items[addr]
- if !yield(addr, child) {
+ for i, idx := range n.Prefixes.AsSlice(&buf) {
+ if !yield(idx, n.Prefixes.Items[i]) {
return
}
}
}
}
-// InsertChild inserts a child node at the specified address.
-// Returns true if a child already existed at addr (overwrite case),
-// false if this is a new insertion.
+// DeletePrefix removes the prefix at the specified index.
+// Returns true if the prefix existed, otherwise false.
+func (n *FastNode[V]) DeletePrefix(idx uint8) (exists bool) {
+ _, exists = n.Prefixes.DeleteAt(idx)
+ return exists
+}
+
+// InsertChild adds a child node at the specified address (0-255).
+// The child can be a *FastNode[V], *LeafNode[V], or *FringeNode[V].
+// Returns true if a child already existed at that address.
func (n *FastNode[V]) InsertChild(addr uint8, child any) (exists bool) {
- if p := n.Children.Items[addr]; p != nil {
- // Reuse existing *any slot to cut allocations and GC churn
- *p = child // overwrite
- return true
+ var rank0 int
+ rank0, exists = n.Children.InsertAt(addr, child)
+ if exists {
+ // Update only: the value at addr is overwritten in-place by InsertAt.
+ // childRankCache[addr] is not refreshed because the rank is unchanged
+ // the position of addr in the sparse slice does not shift on an update.
+ return
}
- n.Children.Set(addr)
- n.CldCount++
-
- // pointer to any reduces per-slot memory for nil entries versus storing `any` directly.
- p := new(any)
- *p = child
- n.Children.Items[addr] = p
+ // new child inserted? cache the rank value for this addr
+ //nolint:gosec // G115: integer overflow conversion int -> uint8
+ n.childRankCache[addr] = uint8(rank0)
- return false
+ // increment all cached ranks after addr
+ for i := 255; i > int(addr); i-- {
+ n.childRankCache[i]++
+ }
+ return
}
// DeleteChild removes the child node at the specified address.
// This operation is idempotent - removing a non-existent child is safe.
func (n *FastNode[V]) DeleteChild(addr uint8) (exists bool) {
- if n.Children.Items[addr] == nil {
- return false
- }
- n.CldCount--
-
- n.Children.Clear(addr)
- n.Children.Items[addr] = nil
- return true
-}
+ _, exists = n.Children.DeleteAt(addr)
-// InsertPrefix adds or updates a routing entry at the specified index with the given value.
-// It returns true if a prefix already existed at that index (indicating an update),
-// false if this is a new insertion.
-func (n *FastNode[V]) InsertPrefix(idx uint8, val V) (exists bool) {
- if exists = n.Prefixes.Test(idx); !exists {
- n.Prefixes.Set(idx)
- n.PfxCount++
+ // nothing deleted
+ if !exists {
+ return exists
}
- // insert or update
-
- // To ensure allot works as intended, every unique prefix in the
- // FastNode must point to a distinct value pointer, even for identical values.
- // Using new() and assignment guarantees each inserted prefix gets its own address,
- valPtr := new(V)
- *valPtr = val
-
- oldValPtr := n.Prefixes.Items[idx]
-
- // overwrite oldValPtr with valPtr
- n.allot(idx, oldValPtr, valPtr)
+ // decrement all cached ranks after addr
+ for i := 255; i > int(addr); i-- {
+ n.childRankCache[i]--
+ }
return exists
}
-// GetPrefix returns the value for the given prefix index and true if it exists.
-// If no prefix exists at idx, returns the zero value and false.
-func (n *FastNode[V]) GetPrefix(idx uint8) (val V, exists bool) {
- if exists = n.Prefixes.Test(idx); exists {
- val = *n.Prefixes.Items[idx]
+// GetChild retrieves the child node at the specified address.
+// Returns the child and true if found, or nil and false if not present.
+func (n *FastNode[V]) GetChild(addr uint8) (any, bool) {
+ if n.Children.Test(addr) {
+ rank0 := n.childRankCache[addr]
+ return n.Children.Items[rank0], true
}
- return val, exists
+ return nil, false
}
-// MustGetPrefix returns the value for the given prefix index.
-// Panics if no prefix exists at idx. This method should only be called
-// when the caller has verified the prefix exists.
-func (n *FastNode[V]) MustGetPrefix(idx uint8) V {
- return *n.Prefixes.Items[idx]
+// MustGetChild retrieves the child at addr using the pre-cached rank stored in
+// childRankCache[addr] for a direct O(1) array access without an existence check.
+//
+// The caller must guarantee that addr is present (Children.Test(addr) == true).
+// If addr is absent, childRankCache[addr] contains the number of occupied
+// addresses less than addr (maintained by InsertChild/DeleteChild), so the
+// behaviour is undefined: either a wrong child is returned silently, or the
+// call panics with an index-out-of-range error.
+func (n *FastNode[V]) MustGetChild(addr uint8) any {
+ rank0 := n.childRankCache[addr]
+ return n.Children.Items[rank0]
}
-// AllIndices returns an iterator over all prefix entries.
-// Each iteration yields the prefix index (uint8) and its associated value (V).
-func (n *FastNode[V]) AllIndices() iter.Seq2[uint8, V] {
- return func(yield func(uint8, V) bool) {
+// AllChildren returns an iterator over all child nodes.
+// Each iteration yields the child's address (uint8) and the child node (any).
+func (n *FastNode[V]) AllChildren() iter.Seq2[uint8, any] {
+ return func(yield func(addr uint8, child any) bool) {
var buf [256]uint8
- for _, idx := range n.Prefixes.AsSlice(&buf) {
- val := n.MustGetPrefix(idx)
- if !yield(idx, val) {
+ addrs := n.Children.AsSlice(&buf)
+ for i, addr := range addrs {
+ if !yield(addr, n.Children.Items[i]) {
return
}
}
}
}
-// DeletePrefix removes the route at the given index.
-// Returns true if the prefix existed, otherwise false.
-func (n *FastNode[V]) DeletePrefix(idx uint8) (exists bool) {
- if exists = n.Prefixes.Test(idx); !exists {
- // Route entry doesn't exist
- return exists
- }
- n.PfxCount--
-
- valPtr := n.Prefixes.Items[idx]
- parentValPtr := n.Prefixes.Items[idx>>1]
-
- // delete -> overwrite valPtr with parentValPtr
- n.allot(idx, valPtr, parentValPtr)
-
- n.Prefixes.Clear(idx)
- return true
-}
-
-// Contains returns true if the given index has any matching longest-prefix
-// in the current node's prefix table.
+// Contains returns true if an index (idx) has any matching longest-prefix
+// in the current node’s prefix table.
//
-// This function performs a presence check using the ART algorithm's
-// hierarchical prefix structure. It tests whether any ancestor prefix
-// exists for the given index by probing the slot at idx (children inherit
-// ancestor pointers via allot).
-func (n *FastNode[V]) Contains(idx uint8) (ok bool) {
- return n.Prefixes.Items[idx] != nil
-}
-
-// Lookup performs a longest-prefix match (LPM) Lookup for the given index
-// within the current node's prefix table in O(1).
+// This function performs a presence check without retrieving the associated value.
+// It is faster than a full lookup, as it only tests for intersection with the
+// backtracking bitset for the given index.
//
-// The function returns the matched value and true if a matching prefix exists;
-// otherwise, it returns the zero value and false. The Lookup uses the ART
-// algorithm's hierarchical structure to find the most specific
-// matching prefix.
-func (n *FastNode[V]) Lookup(idx uint8) (val V, ok bool) {
- if valPtr := n.Prefixes.Items[idx]; valPtr != nil {
- return *valPtr, true
- }
- return val, ok
+// The prefix table is structured as a complete binary tree (CBT), and LPM testing
+// is done via a bitset operation that maps the traversal path from the given index
+// toward its possible ancestors.
+func (n *FastNode[V]) Contains(idx uint8) bool {
+ return n.Prefixes.Intersects(&lpm.LookupTbl[idx])
}
// LookupIdx performs a longest-prefix match (LPM) lookup for the given index (idx)
@@ -244,64 +181,35 @@ func (n *FastNode[V]) Lookup(idx uint8) (val V, ok bool) {
// The function returns the matched base index, associated value, and true if a
// matching prefix exists at this level; otherwise, ok is false.
//
-// Its semantics are identical to [node.LookupIdx].
+// Internally, the prefix table is organized as a complete binary tree (CBT) indexed
+// via the baseIndex function. Unlike the original ART algorithm, this implementation
+// does not use an allotment-based approach. Instead, it performs CBT backtracking
+// using a bitset-based operation with a precomputed backtracking pattern specific to idx.
func (n *FastNode[V]) LookupIdx(idx uint8) (top uint8, val V, ok bool) {
// top is the idx of the longest-prefix-match
if top, ok = n.Prefixes.IntersectionTop(&lpm.LookupTbl[idx]); ok {
- return top, *n.Prefixes.Items[top], true
+ return top, n.MustGetPrefix(top), true
}
return top, val, ok
}
-// allot updates entries whose stored valPtr matches oldValPtr, in the
-// subtree rooted at idx. Matching entries have their stored oldValPtr set to
-// valPtr, and their value set to val.
-//
-// allot is the core of the ART algorithm, enabling efficient insertion/deletion
-// while preserving very fast lookups.
-//
-// Example of (uninterrupted) allotment sequence:
-//
-// addr/bits: 0/5 -> {0/5, 0/6, 4/6, 0/7, 2/7, 4/7, 6/7}
-// ╭────╮╭─────────┬────╮
-// idx: 32 -> 32 64 65 128 129 130 131
-// ╰─────────╯╰─────────────┴────╯
-//
-// Using an iterative form ensures better inlining opportunities.
-func (n *FastNode[V]) allot(idx uint8, oldValPtr, valPtr *V) {
- // iteration with stack instead of recursion
- stack := make([]uint8, 0, 256)
-
- // start idx
- stack = append(stack, idx)
-
- for i := 0; i < len(stack); i++ {
- idx = stack[i]
-
- // stop this allot path, idx already points to a more specific route.
- if n.Prefixes.Items[idx] != oldValPtr {
- continue // take next path from stack
- }
-
- // overwrite
- n.Prefixes.Items[idx] = valPtr
-
- // max idx is 255, so stop the duplication at 128 and above
- if idx >= 128 {
- continue
- }
-
- // child nodes, it's a complete binary tree
- // left: idx*2
- // right: (idx*2)+1
- stack = append(stack, idx<<1, (idx<<1)+1)
- }
+// Lookup is just a simple wrapper for LookupIdx.
+func (n *FastNode[V]) Lookup(idx uint8) (val V, ok bool) {
+ _, val, ok = n.LookupIdx(idx)
+ return val, ok
}
-// CloneFlat returns a shallow copy of the current FastNode[V],
-// Its semantics are identical to [bartNode.CloneFlat] but the
-// implementation is more complex.
-func (n *FastNode[V]) CloneFlat(cloneFn value.CloneFunc[V]) *FastNode[V] {
+// CloneFlat returns a shallow copy of the current node, optionally performing deep copies of values.
+//
+// If cloneFn is nil, the stored values in prefixes are copied directly without modification.
+// Otherwise, cloneFn is applied to each stored value for deep cloning.
+// Child nodes are cloned shallowly: LeafNode and FringeNode children are cloned via their clone methods,
+// but child nodes of type *FastNode[V] (subnodes) are assigned as-is without recursive cloning.
+// This method does not recursively clone descendants beyond the immediate children.
+//
+// Note: The returned node is a new instance with copied slices but only shallow copies of nested nodes,
+// except for LeafNode and FringeNode children which are cloned according to cloneFn.
+func (n *FastNode[V]) CloneFlat(cloneFn func(V) V) *FastNode[V] {
if n == nil {
return nil
}
@@ -311,43 +219,32 @@ func (n *FastNode[V]) CloneFlat(cloneFn value.CloneFunc[V]) *FastNode[V] {
return c
}
- // Copy counters and bitsets (by value).
- c.PfxCount = n.PfxCount
- c.CldCount = n.CldCount
- c.Prefixes.BitSet256 = n.Prefixes.BitSet256
- c.Children.BitSet256 = n.Children.BitSet256
-
- // it's a clone of the prefixes ...
- // but the allot algorithm makes it more difficult
- // see also insertPrefix
- for idx, val := range n.AllIndices() {
- newValPtr := new(V)
-
- if cloneFn == nil {
- *newValPtr = val // just copy the value
- } else {
- *newValPtr = cloneFn(val) // clone the value
- }
+ // copy ...
+ c.Prefixes = *(n.Prefixes.Copy())
- oldValPtr := c.Prefixes.Items[idx] // likely nil initially
- c.allot(idx, oldValPtr, newValPtr)
+ // ... and clone the values
+ if cloneFn != nil {
+ for i, v := range c.Prefixes.Items {
+ c.Prefixes.Items[i] = cloneFn(v)
+ }
}
- // flat clone of the children
- for addr, kidAny := range n.AllChildren() {
- switch kid := kidAny.(type) {
- case *FastNode[V]:
- // link with new *any pointer
- c.Children.Items[addr] = &kidAny
+ // copy ...
+ c.childRankCache = n.childRankCache
+ c.Children = *(n.Children.Copy())
+ // Iterate over children to flat clone leaf/fringe nodes;
+ // for *FastNode[V] children, keep shallow references (no recursive clone)
+ for i, anyKid := range c.Children.Items {
+ switch kid := anyKid.(type) {
+ case *FastNode[V]:
+ // Shallow copy
case *LeafNode[V]:
- leafAny := any(kid.CloneLeaf(cloneFn))
- c.Children.Items[addr] = &leafAny
-
+ // Clone leaf nodes, applying cloneFn as needed
+ c.Children.Items[i] = kid.CloneLeaf(cloneFn)
case *FringeNode[V]:
- fringeAny := any(kid.CloneFringe(cloneFn))
- c.Children.Items[addr] = &fringeAny
-
+ // Clone fringe nodes, applying cloneFn as needed
+ c.Children.Items[i] = kid.CloneFringe(cloneFn)
default:
panic("logic error, wrong node type")
}
@@ -356,9 +253,21 @@ func (n *FastNode[V]) CloneFlat(cloneFn value.CloneFunc[V]) *FastNode[V] {
return c
}
-// CloneRec performs a recursive deep copy of the FastNode[V] and all its descendants.
-// Its semantics are identical to [bartNode.cloneRec].
-func (n *FastNode[V]) CloneRec(cloneFn value.CloneFunc[V]) *FastNode[V] {
+// CloneRec performs a recursive deep copy of the node and all its descendants.
+//
+// If cloneFn is nil, the stored values are copied directly without modification.
+// Otherwise cloneFn is applied to each stored value for deep cloning.
+//
+// This method first creates a shallow clone of the current node using CloneFlat,
+// applying cloneFn to values as described there. Then it recursively clones all
+// child nodes of type *FastNode[V], performing a full deep clone down the subtree.
+//
+// Child nodes of type *LeafNode[V] and *FringeNode[V] are already cloned
+// by CloneFlat.
+//
+// Returns a new instance of FastNode[V] which is a complete deep clone of the
+// receiver node with all descendants.
+func (n *FastNode[V]) CloneRec(cloneFn func(V) V) *FastNode[V] {
if n == nil {
return nil
}
@@ -367,11 +276,9 @@ func (n *FastNode[V]) CloneRec(cloneFn value.CloneFunc[V]) *FastNode[V] {
c := n.CloneFlat(cloneFn)
// Recursively clone all child nodes of type *FastNode[V]
- for addr, kidAny := range c.AllChildren() {
- switch kid := kidAny.(type) {
- case *FastNode[V]:
- nodeAny := any(kid.CloneRec(cloneFn))
- c.Children.Items[addr] = &nodeAny
+ for i, kidAny := range c.Children.Items {
+ if kid, ok := kidAny.(*FastNode[V]); ok {
+ c.Children.Items[i] = kid.CloneRec(cloneFn)
}
}
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/fastmethodsgenerated.go b/vendor/github.com/gaissmai/bart/internal/nodes/fastmethodsgenerated.go
index 6b6448a95b..fdd0fdea83 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/fastmethodsgenerated.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/fastmethodsgenerated.go
@@ -1,6 +1,6 @@
// Code generated from file "commonmethods_tmpl.go"; DO NOT EDIT.
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package nodes
@@ -17,65 +17,76 @@ import (
"github.com/gaissmai/bart/internal/value"
)
-// Insert inserts a network prefix and its associated value into the
-// trie starting at the specified byte depth.
+// Insert adds or updates a network prefix and its associated value in the trie.
+// Traversal begins at the specified byte depth.
//
-// The function traverses the prefix address from the given depth and inserts
-// the value either directly into the node's prefix table or as a compressed
-// leaf or fringe node. If a conflicting leaf or fringe exists, it creates
-// a new intermediate node to accommodate both entries.
+// The trie utilizes path compression to conserve memory. A prefix is inserted:
+// - Uncompressed into a node's prefix table at depth == strideCount.
+// - As a path-compressed FringeNode if it qualifies as fringe [IsFringe].
+// - As a path-compressed LeafNode otherwise.
+//
+// When a new prefix collides with an existing compressed node (Leaf or Fringe),
+// Insert resolves the collision by creating a new intermediate node, pushing
+// the existing entry down to the next level, and continuing traversal.
//
// Parameters:
-// - pfx: The network prefix to insert (must be in canonical form)
-// - val: The value to associate with the prefix
-// - depth: The current depth in the trie (0-based byte index)
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
//
-// Returns true if a prefix already existed and was updated, false for new insertions.
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
func (n *FastNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *FastNode[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next trie level.
+ n = kid
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(FastNode[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -83,18 +94,17 @@ func (n *FastNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(FastNode[V])
newNode.InsertPrefix(1, kid.Value)
@@ -108,63 +118,74 @@ func (n *FastNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
panic("unreachable")
}
-// InsertPersist is similar to insert but the receiver isn't modified.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *FastNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix, val V, depth int) (exists bool) {
+// InsertPersist adds or updates a network prefix and its associated value in the trie
+// using Copy-On-Write (COW) semantics. Traversal begins at the specified byte depth.
+//
+// Unlike [Insert], InsertPersist ensures structural integrity of the existing tree
+// by cloning internal nodes along the descent path (Copy-On-Write) before mutation.
+//
+// Parameters:
+// - cloneFn: The function used to clone values (V).
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
+//
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
+func (n *FastNode[V]) InsertPersist(cloneFn func(V) V, pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *FastNode[V]:
- // clone the traversed path
-
- // kid points now to cloned kid
+ // Standard intermediate node: Clone the traversed path to maintain persistence (COW).
+ // We clone the child node before modifying it, then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // replace kid with clone
n.InsertChild(octet, kid)
-
n = kid
- continue // descend down to next trie level
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(FastNode[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -172,18 +193,17 @@ func (n *FastNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(FastNode[V])
newNode.InsertPrefix(1, kid.Value)
@@ -193,162 +213,170 @@ func (n *FastNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix
default:
panic("logic error, wrong node type")
}
-
}
-
panic("unreachable")
}
-// PurgeAndCompress performs bottom-up compression of the trie.
+// PurgeAndCompress performs bottom-up trie maintenance to restore path compression
+// after a deletion. It unwinds the provided stack of parent nodes, identifying
+// nodes that have become sparse (i.e., containing only a single prefix or a single
+// child node) and prunes them by promoting the underlying entries to the parent level.
//
-// The function unwinds the provided stack of parent nodes, checking each level
-// for compression opportunities based on child and prefix count.
-// It may convert:
-// - Nodes with a single prefix into leaf one level above.
-// - Nodes with a single leaf or fringe into leaf one level above.
+// This ensures the trie remains memory-efficient by collapsing redundant intermediate
+// nodes back into path-compressed LeafNodes or FringeNodes whenever possible.
//
// Parameters:
-// - stack: Array of parent nodes to process during unwinding
-// - octets: The path of octets taken to reach the current position
-// - is4: True for IPv4 processing, false for IPv6
+// - stack: Array of parent nodes to process during bottom-up unwinding.
+// - octets: The full path of octets leading to the current node.
+// - is4: True for IPv4 processing, false for IPv6.
func (n *FastNode[V]) PurgeAndCompress(stack []*FastNode[V], octets []uint8, is4 bool) {
- // unwind the stack
+ // Iterate backwards through the ancestor stack to prune nodes from the bottom up.
for depth := len(stack) - 1; depth >= 0; depth-- {
parent := stack[depth]
octet := octets[depth]
+ // Check if the current node is redundant.
+ // A node may be redundant if it contains exactly one entry (either a prefix or
+ // a compressed child node).
pfxCount := n.PrefixCount()
childCount := n.ChildCount()
+ // If it contains more than one entry, it is always structurally significant and cannot be pruned.
if pfxCount+childCount > 1 {
return
}
switch {
case childCount == 1:
- singleAddr, _ := n.Children.FirstSet() // single addr must be first bit set
+ // The node has exactly one child. We determine if it is a path node,
+ // a compressed LeafNode, or a compressed FringeNode.
+ singleAddr, _ := n.Children.FirstSet()
anyKid := n.MustGetChild(singleAddr)
switch kid := anyKid.(type) {
case *FastNode[V]:
- // fast exit, we are at an intermediate path node
- // no further delete/compress upwards the stack is possible
+ // The child is an intermediate path node; the tree structure is required
+ // at this level. Compression cannot proceed further up.
return
case *LeafNode[V]:
- // just one leaf, delete this node and reinsert the leaf above
+ // The child is a compressed LeafNode. Prune the current node
+ // and re-insert the leaf into the parent to elevate it.
parent.DeleteChild(octet)
-
- // ... (re)insert the leaf at parents depth
parent.Insert(kid.Prefix, kid.Value, depth)
case *FringeNode[V]:
- // just one fringe, delete this node and reinsert the fringe as leaf above
+ // The child is a compressed FringeNode. Prune the current node
+ // and re-insert the fringe as a leaf into the parent.
parent.DeleteChild(octet)
- // rebuild the prefix with octets, depth, ip version and addr
- // depth is the parent's depth, so add +1 here for the kid
- // lastOctet in cidrForFringe is the only addr (singleAddr)
+ // Reconstruct the full prefix for the fringe, as path compression
+ // requires the entire CIDR path, not just the remainder.
+ // depth is the parent's depth, so we offset by 1 for the kid's position.
fringePfx := CidrForFringe(octets, depth+1, is4, singleAddr)
- // ... (re)reinsert prefix/value at parents depth
parent.Insert(fringePfx, kid.Value, depth)
}
case pfxCount == 1:
- // just one prefix, delete this node and reinsert the idx as leaf above
+ // The node has exactly one prefix. Prune the node and elevate the
+ // prefix to the parent level as a leaf/fringe.
parent.DeleteChild(octet)
- // get prefix back from idx ...
- idx, _ := n.Prefixes.FirstSet() // single idx must be first bit set
+ // Retrieve the single prefix stored in this node.
+ idx, _ := n.Prefixes.FirstSet()
val := n.MustGetPrefix(idx)
- // ... and octet path
+ // Reconstruct the prefix from the path for re-insertion.
path := StridePath{}
copy(path[:], octets)
-
- // depth is the parent's depth, so add +1 here for the kid
pfx := CidrFromPath(path, depth+1, is4, idx)
- // ... (re)insert prefix/value at parents depth
parent.Insert(pfx, val, depth)
+ default:
+ panic("unreachable")
}
- // climb up the stack
+ // Move up to the next parent in the stack to continue pruning.
n = parent
}
}
-// Delete deletes the prefix and returns true if the prefix existed,
-// or false otherwise. The prefix must be in canonical form.
+// Delete removes the prefix from the trie rooted at n and returns true if the
+// prefix existed, false if it was not found. The prefix must be in canonical
+// (masked) form.
+//
+// The trie uses path compression, so a prefix may be stored in one of three ways:
+// - In the current node's prefix table when the prefix length aligns exactly
+// with the stride boundary at this depth (depth == strideCount).
+// - As a path-compressed FringeNode in a child slot for stride-aligned prefixes
+// (e.g. /8, /16, /24); occurs at depth == strideCount-1.
+// - As a path-compressed LeafNode in a child slot for prefixes otherwise.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
func (n *FastNode[V]) Delete(pfx netip.Prefix) (exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
- ip := pfx.Addr()
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // record the nodes on the path to the deleted node, needed to purge
- // and/or path compress nodes after the deletion of a prefix
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
stack := [MaxTreeDepth]*FastNode[V]{}
- // find the trie node
for depth, octet := range octets {
- depth = depth & DepthMask // BCE, Delete must be fast
+ depth &= DepthMask // BCE hint; keep Delete on the fast path
- // push current node on stack for path recording
- stack[depth] = n
+ stack[depth] = n // record current node before descending
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- // try to delete prefix in trie node
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
return true
}
+ // no child node exists at this octet; the prefix is not in the trie
if !n.Children.Test(octet) {
return false
}
+
+ // A child node exists at this octet path, retrieve it.
kid := n.MustGetChild(octet)
- // kid is node or leaf or fringe at octet
switch kid := kid.(type) {
case *FastNode[V]:
- n = kid // descend down to next trie level
+ n = kid // descend to the next trie level
case *FringeNode[V]:
- // if pfx is no fringe at this depth, fast exit
- if !IsFringe(depth, pfx) {
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // pfx is fringe at depth, delete fringe
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Attention: pfx must be masked to be comparable!
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
return false
}
- // prefix is equal leaf, delete leaf
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
@@ -359,142 +387,150 @@ func (n *FastNode[V]) Delete(pfx netip.Prefix) (exists bool) {
panic("unreachable")
}
-// DeletePersist is similar to delete but does not mutate the original trie.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *FastNode[V]) DeletePersist(cloneFn value.CloneFunc[V], pfx netip.Prefix) (exists bool) {
- ip := pfx.Addr() // the pfx must be in canonical form
+// DeletePersist removes the prefix from the trie rooted at n using Copy-On-Write (COW) semantics.
+// It returns true if the prefix existed, false if it was not found. The prefix must be in
+// canonical (masked) form.
+//
+// Like [Delete], this method uses path compression. However, DeletePersist ensures
+// the structural integrity of the existing tree by cloning internal nodes along the
+// descent path (COW) before mutation.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
+func (n *FastNode[V]) DeletePersist(cloneFn func(V) V, pfx netip.Prefix) (exists bool) {
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // Stack to keep track of cloned nodes along the path,
- // needed for purge and path compression after delete.
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
+ // Since this is a COW operation, we store the cloned nodes here.
stack := [MaxTreeDepth]*FastNode[V]{}
- // Traverse the trie to locate the prefix to delete.
for depth, octet := range octets {
- // Keep track of the cloned node at current depth.
- stack[depth] = n
+ depth &= DepthMask // BCE hint; keep DeletePersist on the fast path
+ stack[depth] = n // record current node before descending
- if depth == lastOctetPlusOne {
- // Attempt to delete the prefix from the node's prefixes.
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
- // Prefix not found, nothing deleted.
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // After deletion, purge nodes and compress the path if needed.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
}
- addr := octet
-
- // If child node doesn't exist, no prefix to delete.
- if !n.Children.Test(addr) {
+ // no child node exists at this octet; the prefix is not in the trie
+ if !n.Children.Test(octet) {
return false
}
- // Fetch child node at current address.
- kid := n.MustGetChild(addr)
+ // A child node exists at this octet path, retrieve it to either continue
+ // our descent or perform a persistent delete on a compressed node.
+ kid := n.MustGetChild(octet)
switch kid := kid.(type) {
case *FastNode[V]:
- // Clone the internal node for copy-on-write.
+ // Standard intermediate node: Clone the traversed path to maintain
+ // persistence (COW). We clone the child node before modifying it,
+ // then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // Replace child with cloned node.
- n.InsertChild(addr, kid)
-
- // Descend to cloned child node.
+ n.InsertChild(octet, kid)
n = kid
continue
case *FringeNode[V]:
- // Reached a path compressed fringe.
- if !IsFringe(depth, pfx) {
- // Prefix to delete not found here.
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // Delete the fringe node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Reached a path compressed leaf node.
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
- // Leaf prefix does not match; nothing to delete.
return false
}
- // Delete leaf node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
- // Unexpected node type indicates a logic error.
panic("logic error, wrong node type")
}
}
- // Should never happen: traversal always returns or panics inside loop.
panic("unreachable")
}
// Get retrieves the value associated with the given network prefix.
-// Returns the stored value and true if the prefix exists in this node,
-// zero value and false if the prefix is not found.
+// Traversal descends through the trie using the prefix's octets.
+//
+// The lookup handles path compression transparently:
+// - If the path matches an internal node at the target stride, the value is retrieved
+// from the node's prefix table.
+// - If the path leads to a compressed LeafNode or FringeNode, the function verifies
+// the prefix match before returning the value.
//
// Parameters:
-// - pfx: The network prefix to look up (must be in canonical form)
+// - pfx: The network prefix to look up (must be in canonical form).
//
// Returns:
-// - val: The value associated with the prefix (zero value if not found)
-// - exists: True if the prefix was found, false otherwise
+// - val: The value associated with the prefix (zero value if not found).
+// - exists: True if the prefix was found, false otherwise.
func (n *FastNode[V]) Get(pfx netip.Prefix) (val V, exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
+ // The prefix must be provided in canonical (masked) form for correct trie traversal.
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the trie node
+ // Traverse the trie octet by octet based on the prefix path.
for depth, octet := range octets {
- if depth == lastOctetPlusOne {
- return n.GetPrefix(art.PfxToIdx(octet, lastBits))
+ // At the target stride boundary, the prefix is expected in this node's
+ // prefix table.
+ if depth == strideCount {
+ return n.GetPrefix(art.PfxToIdx(octet, modBits))
}
+ // If no child exists at this path, the prefix is not in the trie.
kidAny, ok := n.GetChild(octet)
if !ok {
return val, false
}
- // kid is node or leaf or fringe at octet
+ // Identify the node type at this path segment.
switch kid := kidAny.(type) {
case *FastNode[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next level.
+ n = kid
case *FringeNode[V]:
- // reached a path compressed fringe, stop traversing
- if IsFringe(depth, pfx) {
+ // Reached a path-compressed FringeNode.
+ // Verify if the prefix qualifies as a fringe at this depth to return a match.
+ if IsFringe(depth, pfxLen) {
return kid.Value, true
}
return val, false
case *LeafNode[V]:
- // reached a path compressed prefix, stop traversing
+ // Reached a path-compressed LeafNode.
+ // Check if the stored prefix matches the lookup prefix exactly.
if kid.Prefix == pfx {
return kid.Value, true
}
@@ -512,7 +548,7 @@ func (n *FastNode[V]) Get(pfx netip.Prefix) (val V, exists bool) {
// The callback receives the current value (if found) and existence flag, and returns
// a new value and deletion flag.
//
-// modify returns the size delta (-1, 0, +1).
+// Modify returns the size delta (-1, 0, +1).
// This method handles path traversal, node creation for new paths, and automatic
// purge/compress operations after deletions.
//
@@ -526,9 +562,10 @@ func (n *FastNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
var zero V
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// record the nodes on the path to the deleted node, needed to purge
// and/or path compress nodes after the deletion of a prefix
@@ -536,16 +573,15 @@ func (n *FastNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
// find the proper trie node to update prefix
for depth, octet := range octets {
- depth = depth & DepthMask // BCE
+ depth &= DepthMask // BCE
// push current node on stack for path recording
stack[depth] = n
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // stride for this prefix. Insert or update it directly in this node's prefix table.
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
oldVal, existed := n.GetPrefix(idx)
newVal, del := cb(oldVal, existed)
@@ -585,7 +621,7 @@ func (n *FastNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
}
// insert
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
n.InsertChild(octet, NewFringeNode(newVal))
} else {
n.InsertChild(octet, NewLeafNode(pfx, newVal))
@@ -644,7 +680,7 @@ func (n *FastNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
case *FringeNode[V]:
// update existing value if prefix is fringe
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
newVal, del := cb(kid.Value, true)
if !del {
kid.Value = newVal
@@ -774,8 +810,8 @@ func (n *FastNode[V]) EqualRec(o *FastNode[V]) bool {
//
// It returns immediately if n is nil or empty. For each visited internal node
// it calls dump to write the node's representation, then iterates its child
-// addresses and recurses into children that implement nodeDumper[V] (internal
-// subnodes). The path slice and depth together represent the byte-wise path
+// addresses and recurses into children of type *FastNode[V] (internal subnodes).
+// The path slice and depth together represent the byte-wise path
// from the root to the current node; depth is incremented for each recursion.
// The is4 flag controls IPv4/IPv6 formatting used by dump.
func (n *FastNode[V]) DumpRec(w io.Writer, path StridePath, depth int, is4 bool) {
@@ -803,8 +839,8 @@ func (n *FastNode[V]) dump(w io.Writer, path StridePath, depth int, is4 bool) {
bits := depth * strideLen
indent := strings.Repeat(".", depth)
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// node type with depth and octet path and bits.
fmt.Fprintf(w, "\n%s[%s] depth: %d path: [%s] / %d\n",
@@ -967,7 +1003,7 @@ func (n *FastNode[V]) DumpString(octets []uint8, depth int, is4 bool) string {
// - stopNode: has children but no subnodes (nodes == 0)
// - halfNode: contains at least one leaf or fringe and also has subnodes, but
// no prefixes
-// - fullNode: has prefixes or leaves/fringes and also has subnodes
+// - fullNode: has prefixes and also has subnodes
// - pathNode: has subnodes only (no prefixes, leaves, or fringes)
//
// The order of these checks is significant to ensure the correct classification.
@@ -1024,7 +1060,7 @@ func (n *FastNode[V]) Stats() (s StatsT) {
// It walks the node tree recursively and sums immediate counts (prefixes and
// child slots) plus the number of nodes, leaves, and fringe nodes in the
// subtree. If n is nil or empty, a zeroed stats is returned. The returned
-// stats.nodes includes the current node. The function will panic if a child
+// SubNodes count includes the current node. The function will panic if a child
// has an unexpected concrete type.
func (n *FastNode[V]) StatsRec() (s StatsT) {
if n == nil || n.IsEmpty() {
@@ -1080,8 +1116,8 @@ func (n *FastNode[V]) FprintRec(w io.Writer, parent TrieItem[V], pad string) err
return CmpPrefix(a.Cidr, b.Cidr)
})
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// for all direct item under this node ...
for i, item := range directItems {
@@ -1178,7 +1214,7 @@ func (n *FastNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
path[depth] = addr
directItems = append(directItems, kid.DirectItemsRec(0, path, depth+1, is4)...)
- case *LeafNode[V]: // path-compressed child, stop's recursion for this child
+ case *LeafNode[V]: // path-compressed child, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1187,7 +1223,7 @@ func (n *FastNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
}
directItems = append(directItems, item)
- case *FringeNode[V]: // path-compressed fringe, stop's recursion for this child
+ case *FringeNode[V]: // path-compressed fringe, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1221,9 +1257,9 @@ func (n *FastNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
// The merge operation is destructive on the receiver n, but leaves the source node o unchanged.
//
// Returns the number of duplicate prefixes that were overwritten during merging.
-func (n *FastNode[V]) UnionRec(cloneFn value.CloneFunc[V], o *FastNode[V], depth int) (duplicates int) {
+func (n *FastNode[V]) UnionRec(cloneFn func(V) V, o *FastNode[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1254,9 +1290,9 @@ func (n *FastNode[V]) UnionRec(cloneFn value.CloneFunc[V], o *FastNode[V], depth
}
// UnionRecPersist is similar to unionRec but performs an immutable union of nodes.
-func (n *FastNode[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *FastNode[V], depth int) (duplicates int) {
+func (n *FastNode[V]) UnionRecPersist(cloneFn func(V) V, o *FastNode[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1305,7 +1341,7 @@ func (n *FastNode[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *FastNode[V]
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *FastNode[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *FastNode[V]) handleMatrix(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*FastNode[V])
@@ -1422,7 +1458,7 @@ func (n *FastNode[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool,
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *FastNode[V]) handleMatrixPersist(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *FastNode[V]) handleMatrixPersist(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*FastNode[V])
@@ -1654,9 +1690,7 @@ func (n *FastNode[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield f
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, childAddr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1691,9 +1725,7 @@ func (n *FastNode[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield f
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, addr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1879,9 +1911,10 @@ func (n *FastNode[V]) EachSubnet(octets []byte, depth int, is4 bool, pfxIdx uint
// the iteration early.
func (n *FastNode[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// stack of the traversed nodes for reverse ordering of supernets
stack := [MaxTreeDepth]*FastNode[V]{}
@@ -1894,7 +1927,7 @@ func (n *FastNode[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V) bo
LOOP:
for depth, octet = range octets {
// stepped one past the last stride of interest; back up to last and exit
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
depth--
break
}
@@ -1955,11 +1988,10 @@ LOOP:
// all others are just host routes
var idx uint8
octet = octets[depth]
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx = art.PfxToIdx(octet, lastBits)
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
+ if depth == strideCount {
+ idx = art.PfxToIdx(octet, modBits)
} else {
idx = art.OctetToIdx(octet)
}
@@ -1996,17 +2028,18 @@ LOOP:
func (n *FastNode[V]) Subnets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
// values derived from pfx
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// find the trie node
for depth, octet := range octets {
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
// so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
n.EachSubnet(octets, depth, is4, idx, yield)
return
}
@@ -2124,7 +2157,7 @@ func (n *FastNode[V]) Overlaps(o *FastNode[V], depth int) bool {
// OverlapsRoutes compares the prefix sets of two nodes (n and o).
//
// It first checks for direct bitset intersection (identical indices),
-// then walks both prefix sets using lpmTest to detect if any
+// then walks both prefix sets using the Contains method to detect if any
// of the n-prefixes is contained in o, or vice versa.
func (n *FastNode[V]) OverlapsRoutes(o *FastNode[V]) bool {
// some prefixes are identical, trivial overlap
@@ -2267,19 +2300,20 @@ func (n *FastNode[V]) OverlapsSameChildren(o *FastNode[V], depth int) bool {
// trie traversal across varying prefix lengths and compression levels.
func (n *FastNode[V]) OverlapsPrefixAtDepth(pfx netip.Prefix, depth int) bool {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
for ; depth < len(octets); depth++ {
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
break
}
octet := octets[depth]
// full octet path in node trie, check overlap with last prefix octet
- if depth == lastOctetPlusOne {
- return n.OverlapsIdx(art.PfxToIdx(octet, lastBits))
+ if depth == strideCount {
+ return n.OverlapsIdx(art.PfxToIdx(octet, modBits))
}
// test if any route overlaps prefix´ so far
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/lite.go b/vendor/github.com/gaissmai/bart/internal/nodes/lite.go
index f5fcbdcaf7..df889e7a3e 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/lite.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/lite.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package nodes
@@ -9,29 +9,17 @@ import (
"github.com/gaissmai/bart/internal/bitset"
"github.com/gaissmai/bart/internal/lpm"
"github.com/gaissmai/bart/internal/sparse"
- "github.com/gaissmai/bart/internal/value"
)
-// LiteNode is a trie level node in the multibit routing table.
-//
-// Each LiteNode contains two conceptually different bitset-based arrays:
-// - Prefixes: a BitSet256 tracking which prefix indices are occupied,
-// with Count tracking the number of active entries.
-// - Children: holding subtries or path-compressed leaves/fringes with
-// a branching factor of 256 (8 bits per stride).
-//
-// Entries in Children may be:
-// - *LiteNode[V] -> internal child node for further traversal
-// - *LeafNode[V] -> path-comp. node (depth < maxDepth - 1)
-// - *FringeNode[V] -> path-comp. node (depth == maxDepth - 1, stride-aligned)
-//
-// Note: The type parameter V is a phantom type used solely for common
-// method generation; LiteNode stores no values.
+// LiteNode is a space-optimized version of [BartNode] that tracks prefix existence
+// without storing associated values.
type LiteNode[V any] struct {
Children sparse.Array256[any]
Prefixes struct {
- // no values
+ // BitSet256 tracks the presence of prefixes at this level.
bitset.BitSet256
+ // Count maintains the current number of set bits, updated on modification
+ // to avoid expensive population counting.
Count uint16
}
}
@@ -57,7 +45,7 @@ func (n *LiteNode[V]) ChildCount() int {
}
// InsertPrefix adds a routing entry at the specified index.
-// It returns true if a prefix already existed at that index
+// It returns true if a prefix already existed at that index,
// false if this is a new insertion.
func (n *LiteNode[V]) InsertPrefix(idx uint8, _ V) (exists bool) {
if exists = n.Prefixes.Test(idx); exists {
@@ -68,13 +56,14 @@ func (n *LiteNode[V]) InsertPrefix(idx uint8, _ V) (exists bool) {
return exists
}
-// prefix is set at the given index.
func (n *LiteNode[V]) GetPrefix(idx uint8) (_ V, exists bool) {
+ // no docstring by intention
exists = n.Prefixes.Test(idx)
return
}
func (n *LiteNode[V]) MustGetPrefix(idx uint8) (_ V) {
+ // no docstring by intention
return
}
@@ -107,7 +96,8 @@ func (n *LiteNode[V]) DeletePrefix(idx uint8) (exists bool) {
// The child can be a *LiteNode[V], *LeafNode, or *FringeNode.
// Returns true if a child already existed at that address.
func (n *LiteNode[V]) InsertChild(addr uint8, child any) (exists bool) {
- return n.Children.InsertAt(addr, child)
+ _, exists = n.Children.InsertAt(addr, child)
+ return
}
// GetChild retrieves the child node at the specified address.
@@ -129,8 +119,7 @@ func (n *LiteNode[V]) AllChildren() iter.Seq2[uint8, any] {
var buf [256]uint8
addrs := n.Children.AsSlice(&buf)
for i, addr := range addrs {
- child := n.Children.Items[i]
- if !yield(addr, child) {
+ if !yield(addr, n.Children.Items[i]) {
return
}
}
@@ -171,7 +160,7 @@ func (n *LiteNode[V]) LookupIdx(idx uint8) (top uint8, _ V, ok bool) {
return
}
-// Lookup is just a simple wrapper for lookupIdx.
+// Lookup is just a simple wrapper for LookupIdx.
func (n *LiteNode[V]) Lookup(idx uint8) (_ V, ok bool) {
_, _, ok = n.LookupIdx(idx)
return
@@ -180,7 +169,7 @@ func (n *LiteNode[V]) Lookup(idx uint8) (_ V, ok bool) {
// CloneFlat returns a shallow copy of the current node.
//
// CloneFn is only used for interface satisfaction.
-func (n *LiteNode[V]) CloneFlat(_ value.CloneFunc[V]) *LiteNode[V] {
+func (n *LiteNode[V]) CloneFlat(_ func(V) V) *LiteNode[V] {
if n == nil {
return nil
}
@@ -213,7 +202,7 @@ func (n *LiteNode[V]) CloneFlat(_ value.CloneFunc[V]) *LiteNode[V] {
//
// Returns a new instance of LiteNode[V] which is a complete deep clone of the
// receiver node with all descendants.
-func (n *LiteNode[V]) CloneRec(_ value.CloneFunc[V]) *LiteNode[V] {
+func (n *LiteNode[V]) CloneRec(_ func(V) V) *LiteNode[V] {
if n == nil {
return nil
}
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/litemethodsgenerated.go b/vendor/github.com/gaissmai/bart/internal/nodes/litemethodsgenerated.go
index e1af8585de..c615cd02b2 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/litemethodsgenerated.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/litemethodsgenerated.go
@@ -1,6 +1,6 @@
// Code generated from file "commonmethods_tmpl.go"; DO NOT EDIT.
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package nodes
@@ -17,65 +17,76 @@ import (
"github.com/gaissmai/bart/internal/value"
)
-// Insert inserts a network prefix and its associated value into the
-// trie starting at the specified byte depth.
+// Insert adds or updates a network prefix and its associated value in the trie.
+// Traversal begins at the specified byte depth.
//
-// The function traverses the prefix address from the given depth and inserts
-// the value either directly into the node's prefix table or as a compressed
-// leaf or fringe node. If a conflicting leaf or fringe exists, it creates
-// a new intermediate node to accommodate both entries.
+// The trie utilizes path compression to conserve memory. A prefix is inserted:
+// - Uncompressed into a node's prefix table at depth == strideCount.
+// - As a path-compressed FringeNode if it qualifies as fringe [IsFringe].
+// - As a path-compressed LeafNode otherwise.
+//
+// When a new prefix collides with an existing compressed node (Leaf or Fringe),
+// Insert resolves the collision by creating a new intermediate node, pushing
+// the existing entry down to the next level, and continuing traversal.
//
// Parameters:
-// - pfx: The network prefix to insert (must be in canonical form)
-// - val: The value to associate with the prefix
-// - depth: The current depth in the trie (0-based byte index)
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
//
-// Returns true if a prefix already existed and was updated, false for new insertions.
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
func (n *LiteNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *LiteNode[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next trie level.
+ n = kid
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(LiteNode[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -83,18 +94,17 @@ func (n *LiteNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(LiteNode[V])
newNode.InsertPrefix(1, kid.Value)
@@ -108,63 +118,74 @@ func (n *LiteNode[V]) Insert(pfx netip.Prefix, val V, depth int) (exists bool) {
panic("unreachable")
}
-// InsertPersist is similar to insert but the receiver isn't modified.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *LiteNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix, val V, depth int) (exists bool) {
+// InsertPersist adds or updates a network prefix and its associated value in the trie
+// using Copy-On-Write (COW) semantics. Traversal begins at the specified byte depth.
+//
+// Unlike [Insert], InsertPersist ensures structural integrity of the existing tree
+// by cloning internal nodes along the descent path (Copy-On-Write) before mutation.
+//
+// Parameters:
+// - cloneFn: The function used to clone values (V).
+// - pfx: The network prefix to insert (must be in canonical/masked form).
+// - val: The value to associate with the prefix.
+// - depth: The current depth in the trie (0-based byte index).
+//
+// Returns true if an existing prefix was updated, false if a new insertion occurred.
+func (n *LiteNode[V]) InsertPersist(cloneFn func(V) V, pfx netip.Prefix, val V, depth int) (exists bool) {
ip := pfx.Addr() // the pfx must be in canonical form
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the proper trie node to insert prefix
- // start with prefix octet at depth
+ // Traverse the prefix's octets. Each depth corresponds to an 8-bit stride.
+ // We descend through the trie until we either reach the final stride (depth == strideCount)
+ // or find an empty child slot where we can path-compress the remaining strides.
for ; depth < len(octets); depth++ {
octet := octets[depth]
- // last masked octet: insert/override prefix/val into node
- if depth == lastOctetPlusOne {
- return n.InsertPrefix(art.PfxToIdx(octet, lastBits), val)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // node for this prefix. We insert it directly into this node's prefix table.
+ if depth == strideCount {
+ return n.InsertPrefix(art.PfxToIdx(octet, modBits), val)
}
- // reached end of trie path ...
+ // No child exists at this octet path. Instead of creating intermediate nodes
+ // for the remaining strides, we path-compress the rest of the prefix into a single child slot.
if !n.Children.Test(octet) {
- // insert prefix path compressed as leaf or fringe
- if IsFringe(depth, pfx) {
+ // If the prefix is perfectly aligned with the next stride boundary (e.g., /16 at depth 1),
+ // it acts as a default route for everything below it. We store it as a FringeNode.
+ // Otherwise, it has trailing bits or crosses boundaries, so we store it as a LeafNode.
+ if IsFringe(depth, pfxLen) {
return n.InsertChild(octet, NewFringeNode(val))
}
return n.InsertChild(octet, NewLeafNode(pfx, val))
}
- // ... or descend down the trie
+ // A child already exists at this octet path. Retrieve it to either continue
+ // our descent along the strides or resolve a structural collision with a compressed node.
kid := n.MustGetChild(octet)
- // kid is node or leaf at addr
switch kid := kid.(type) {
case *LiteNode[V]:
- // clone the traversed path
-
- // kid points now to cloned kid
+ // Standard intermediate node: Clone the traversed path to maintain persistence (COW).
+ // We clone the child node before modifying it, then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // replace kid with clone
n.InsertChild(octet, kid)
-
n = kid
- continue // descend down to next trie level
case *LeafNode[V]:
- // reached a path compressed prefix
- // override value in slot if prefixes are equal
+ // Collision with an existing path-compressed LeafNode.
+ // If it's the exact same prefix, simply update the value.
if kid.Prefix == pfx {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the leaf down
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution: the paths diverge.
+ // 1. Create a new intermediate node.
+ // 2. Push the existing leaf down into this new node.
+ // 3. Replace the current child slot with the new node.
+ // 4. Descend into the new node to continue inserting 'pfx'.
newNode := new(LiteNode[V])
newNode.Insert(kid.Prefix, kid.Value, depth+1)
@@ -172,18 +193,17 @@ func (n *LiteNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix
n = newNode
case *FringeNode[V]:
- // reached a path compressed fringe
- // override value in slot if pfx is a fringe
- if IsFringe(depth, pfx) {
+ // Collision with an existing path-compressed FringeNode.
+ // If the incoming prefix is also a fringe at this depth, update the value.
+ if IsFringe(depth, pfxLen) {
kid.Value = val
- // exists
return true
}
- // create new node
- // push the fringe down, it becomes a default route (idx=1)
- // insert new child at current leaf position (addr)
- // descend down, replace n with new child
+ // Collision resolution:
+ // The existing FringeNode acts as a catch-all (default route) for this sub-trie.
+ // To allow the incoming prefix to branch further, we expand the FringeNode
+ // into a full intermediate node and place its value at the default route index (1).
newNode := new(LiteNode[V])
newNode.InsertPrefix(1, kid.Value)
@@ -193,162 +213,170 @@ func (n *LiteNode[V]) InsertPersist(cloneFn value.CloneFunc[V], pfx netip.Prefix
default:
panic("logic error, wrong node type")
}
-
}
-
panic("unreachable")
}
-// PurgeAndCompress performs bottom-up compression of the trie.
+// PurgeAndCompress performs bottom-up trie maintenance to restore path compression
+// after a deletion. It unwinds the provided stack of parent nodes, identifying
+// nodes that have become sparse (i.e., containing only a single prefix or a single
+// child node) and prunes them by promoting the underlying entries to the parent level.
//
-// The function unwinds the provided stack of parent nodes, checking each level
-// for compression opportunities based on child and prefix count.
-// It may convert:
-// - Nodes with a single prefix into leaf one level above.
-// - Nodes with a single leaf or fringe into leaf one level above.
+// This ensures the trie remains memory-efficient by collapsing redundant intermediate
+// nodes back into path-compressed LeafNodes or FringeNodes whenever possible.
//
// Parameters:
-// - stack: Array of parent nodes to process during unwinding
-// - octets: The path of octets taken to reach the current position
-// - is4: True for IPv4 processing, false for IPv6
+// - stack: Array of parent nodes to process during bottom-up unwinding.
+// - octets: The full path of octets leading to the current node.
+// - is4: True for IPv4 processing, false for IPv6.
func (n *LiteNode[V]) PurgeAndCompress(stack []*LiteNode[V], octets []uint8, is4 bool) {
- // unwind the stack
+ // Iterate backwards through the ancestor stack to prune nodes from the bottom up.
for depth := len(stack) - 1; depth >= 0; depth-- {
parent := stack[depth]
octet := octets[depth]
+ // Check if the current node is redundant.
+ // A node may be redundant if it contains exactly one entry (either a prefix or
+ // a compressed child node).
pfxCount := n.PrefixCount()
childCount := n.ChildCount()
+ // If it contains more than one entry, it is always structurally significant and cannot be pruned.
if pfxCount+childCount > 1 {
return
}
switch {
case childCount == 1:
- singleAddr, _ := n.Children.FirstSet() // single addr must be first bit set
+ // The node has exactly one child. We determine if it is a path node,
+ // a compressed LeafNode, or a compressed FringeNode.
+ singleAddr, _ := n.Children.FirstSet()
anyKid := n.MustGetChild(singleAddr)
switch kid := anyKid.(type) {
case *LiteNode[V]:
- // fast exit, we are at an intermediate path node
- // no further delete/compress upwards the stack is possible
+ // The child is an intermediate path node; the tree structure is required
+ // at this level. Compression cannot proceed further up.
return
case *LeafNode[V]:
- // just one leaf, delete this node and reinsert the leaf above
+ // The child is a compressed LeafNode. Prune the current node
+ // and re-insert the leaf into the parent to elevate it.
parent.DeleteChild(octet)
-
- // ... (re)insert the leaf at parents depth
parent.Insert(kid.Prefix, kid.Value, depth)
case *FringeNode[V]:
- // just one fringe, delete this node and reinsert the fringe as leaf above
+ // The child is a compressed FringeNode. Prune the current node
+ // and re-insert the fringe as a leaf into the parent.
parent.DeleteChild(octet)
- // rebuild the prefix with octets, depth, ip version and addr
- // depth is the parent's depth, so add +1 here for the kid
- // lastOctet in cidrForFringe is the only addr (singleAddr)
+ // Reconstruct the full prefix for the fringe, as path compression
+ // requires the entire CIDR path, not just the remainder.
+ // depth is the parent's depth, so we offset by 1 for the kid's position.
fringePfx := CidrForFringe(octets, depth+1, is4, singleAddr)
- // ... (re)reinsert prefix/value at parents depth
parent.Insert(fringePfx, kid.Value, depth)
}
case pfxCount == 1:
- // just one prefix, delete this node and reinsert the idx as leaf above
+ // The node has exactly one prefix. Prune the node and elevate the
+ // prefix to the parent level as a leaf/fringe.
parent.DeleteChild(octet)
- // get prefix back from idx ...
- idx, _ := n.Prefixes.FirstSet() // single idx must be first bit set
+ // Retrieve the single prefix stored in this node.
+ idx, _ := n.Prefixes.FirstSet()
val := n.MustGetPrefix(idx)
- // ... and octet path
+ // Reconstruct the prefix from the path for re-insertion.
path := StridePath{}
copy(path[:], octets)
-
- // depth is the parent's depth, so add +1 here for the kid
pfx := CidrFromPath(path, depth+1, is4, idx)
- // ... (re)insert prefix/value at parents depth
parent.Insert(pfx, val, depth)
+ default:
+ panic("unreachable")
}
- // climb up the stack
+ // Move up to the next parent in the stack to continue pruning.
n = parent
}
}
-// Delete deletes the prefix and returns true if the prefix existed,
-// or false otherwise. The prefix must be in canonical form.
+// Delete removes the prefix from the trie rooted at n and returns true if the
+// prefix existed, false if it was not found. The prefix must be in canonical
+// (masked) form.
+//
+// The trie uses path compression, so a prefix may be stored in one of three ways:
+// - In the current node's prefix table when the prefix length aligns exactly
+// with the stride boundary at this depth (depth == strideCount).
+// - As a path-compressed FringeNode in a child slot for stride-aligned prefixes
+// (e.g. /8, /16, /24); occurs at depth == strideCount-1.
+// - As a path-compressed LeafNode in a child slot for prefixes otherwise.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
func (n *LiteNode[V]) Delete(pfx netip.Prefix) (exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
- ip := pfx.Addr()
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // record the nodes on the path to the deleted node, needed to purge
- // and/or path compress nodes after the deletion of a prefix
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
stack := [MaxTreeDepth]*LiteNode[V]{}
- // find the trie node
for depth, octet := range octets {
- depth = depth & DepthMask // BCE, Delete must be fast
+ depth &= DepthMask // BCE hint; keep Delete on the fast path
- // push current node on stack for path recording
- stack[depth] = n
+ stack[depth] = n // record current node before descending
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- // try to delete prefix in trie node
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
return true
}
+ // no child node exists at this octet; the prefix is not in the trie
if !n.Children.Test(octet) {
return false
}
+
+ // A child node exists at this octet path, retrieve it.
kid := n.MustGetChild(octet)
- // kid is node or leaf or fringe at octet
switch kid := kid.(type) {
case *LiteNode[V]:
- n = kid // descend down to next trie level
+ n = kid // descend to the next trie level
case *FringeNode[V]:
- // if pfx is no fringe at this depth, fast exit
- if !IsFringe(depth, pfx) {
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // pfx is fringe at depth, delete fringe
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Attention: pfx must be masked to be comparable!
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
return false
}
- // prefix is equal leaf, delete leaf
n.DeleteChild(octet)
- // remove now-empty nodes and re-path-compress upwards
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
@@ -359,142 +387,150 @@ func (n *LiteNode[V]) Delete(pfx netip.Prefix) (exists bool) {
panic("unreachable")
}
-// DeletePersist is similar to delete but does not mutate the original trie.
-// Assumes the caller has pre-cloned the root (COW). It clones the
-// internal nodes along the descent path before mutating them.
-func (n *LiteNode[V]) DeletePersist(cloneFn value.CloneFunc[V], pfx netip.Prefix) (exists bool) {
- ip := pfx.Addr() // the pfx must be in canonical form
+// DeletePersist removes the prefix from the trie rooted at n using Copy-On-Write (COW) semantics.
+// It returns true if the prefix existed, false if it was not found. The prefix must be in
+// canonical (masked) form.
+//
+// Like [Delete], this method uses path compression. However, DeletePersist ensures
+// the structural integrity of the existing tree by cloning internal nodes along the
+// descent path (COW) before mutation.
+//
+// After a successful deletion, PurgeAndCompress walks the ancestor stack to prune
+// now-empty nodes and restore path compression upward.
+func (n *LiteNode[V]) DeletePersist(cloneFn func(V) V, pfx netip.Prefix) (exists bool) {
+ ip := pfx.Addr() // pfx must be in canonical (masked) form
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // Stack to keep track of cloned nodes along the path,
- // needed for purge and path compression after delete.
+ // Record ancestor nodes as we descend; PurgeAndCompress uses this stack to
+ // walk back up and clean up empty or re-compressible nodes after deletion.
+ // Since this is a COW operation, we store the cloned nodes here.
stack := [MaxTreeDepth]*LiteNode[V]{}
- // Traverse the trie to locate the prefix to delete.
for depth, octet := range octets {
- // Keep track of the cloned node at current depth.
- stack[depth] = n
+ depth &= DepthMask // BCE hint; keep DeletePersist on the fast path
+ stack[depth] = n // record current node before descending
- if depth == lastOctetPlusOne {
- // Attempt to delete the prefix from the node's prefixes.
- if exists = n.DeletePrefix(art.PfxToIdx(octet, lastBits)); !exists {
- // Prefix not found, nothing deleted.
+ // At the stride boundary, the prefix is stored directly in this node's
+ // prefix table.
+ if depth == strideCount {
+ if exists = n.DeletePrefix(art.PfxToIdx(octet, modBits)); !exists {
return false
}
- // After deletion, purge nodes and compress the path if needed.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
}
- addr := octet
-
- // If child node doesn't exist, no prefix to delete.
- if !n.Children.Test(addr) {
+ // no child node exists at this octet; the prefix is not in the trie
+ if !n.Children.Test(octet) {
return false
}
- // Fetch child node at current address.
- kid := n.MustGetChild(addr)
+ // A child node exists at this octet path, retrieve it to either continue
+ // our descent or perform a persistent delete on a compressed node.
+ kid := n.MustGetChild(octet)
switch kid := kid.(type) {
case *LiteNode[V]:
- // Clone the internal node for copy-on-write.
+ // Standard intermediate node: Clone the traversed path to maintain
+ // persistence (COW). We clone the child node before modifying it,
+ // then replace the current child slot.
kid = kid.CloneFlat(cloneFn)
-
- // Replace child with cloned node.
- n.InsertChild(addr, kid)
-
- // Descend to cloned child node.
+ n.InsertChild(octet, kid)
n = kid
continue
case *FringeNode[V]:
- // Reached a path compressed fringe.
- if !IsFringe(depth, pfx) {
- // Prefix to delete not found here.
+ // A FringeNode holds a single stride-aligned prefix (/8, /16, ...).
+ // If pfx does not qualify as a fringe at this depth, it cannot be here.
+ if !IsFringe(depth, pfxLen) {
return false
}
- // Delete the fringe node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
case *LeafNode[V]:
- // Reached a path compressed leaf node.
+ // A LeafNode holds exactly one path-compressed prefix.
+ // Compare using the canonical (masked) form for an exact match.
if kid.Prefix != pfx {
- // Leaf prefix does not match; nothing to delete.
return false
}
- // Delete leaf node.
- n.DeleteChild(addr)
+ n.DeleteChild(octet)
- // Purge and compress affected path.
+ // prune now-empty nodes and re-compress the path upwards
n.PurgeAndCompress(stack[:depth], octets, is4)
-
return true
default:
- // Unexpected node type indicates a logic error.
panic("logic error, wrong node type")
}
}
- // Should never happen: traversal always returns or panics inside loop.
panic("unreachable")
}
// Get retrieves the value associated with the given network prefix.
-// Returns the stored value and true if the prefix exists in this node,
-// zero value and false if the prefix is not found.
+// Traversal descends through the trie using the prefix's octets.
+//
+// The lookup handles path compression transparently:
+// - If the path matches an internal node at the target stride, the value is retrieved
+// from the node's prefix table.
+// - If the path leads to a compressed LeafNode or FringeNode, the function verifies
+// the prefix match before returning the value.
//
// Parameters:
-// - pfx: The network prefix to look up (must be in canonical form)
+// - pfx: The network prefix to look up (must be in canonical form).
//
// Returns:
-// - val: The value associated with the prefix (zero value if not found)
-// - exists: True if the prefix was found, false otherwise
+// - val: The value associated with the prefix (zero value if not found).
+// - exists: True if the prefix was found, false otherwise.
func (n *LiteNode[V]) Get(pfx netip.Prefix) (val V, exists bool) {
- // invariant, prefix must be masked
-
- // values derived from pfx
+ // The prefix must be provided in canonical (masked) form for correct trie traversal.
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
- // find the trie node
+ // Traverse the trie octet by octet based on the prefix path.
for depth, octet := range octets {
- if depth == lastOctetPlusOne {
- return n.GetPrefix(art.PfxToIdx(octet, lastBits))
+ // At the target stride boundary, the prefix is expected in this node's
+ // prefix table.
+ if depth == strideCount {
+ return n.GetPrefix(art.PfxToIdx(octet, modBits))
}
+ // If no child exists at this path, the prefix is not in the trie.
kidAny, ok := n.GetChild(octet)
if !ok {
return val, false
}
- // kid is node or leaf or fringe at octet
+ // Identify the node type at this path segment.
switch kid := kidAny.(type) {
case *LiteNode[V]:
- n = kid // descend down to next trie level
+ // Standard intermediate node: descend to the next level.
+ n = kid
case *FringeNode[V]:
- // reached a path compressed fringe, stop traversing
- if IsFringe(depth, pfx) {
+ // Reached a path-compressed FringeNode.
+ // Verify if the prefix qualifies as a fringe at this depth to return a match.
+ if IsFringe(depth, pfxLen) {
return kid.Value, true
}
return val, false
case *LeafNode[V]:
- // reached a path compressed prefix, stop traversing
+ // Reached a path-compressed LeafNode.
+ // Check if the stored prefix matches the lookup prefix exactly.
if kid.Prefix == pfx {
return kid.Value, true
}
@@ -512,7 +548,7 @@ func (n *LiteNode[V]) Get(pfx netip.Prefix) (val V, exists bool) {
// The callback receives the current value (if found) and existence flag, and returns
// a new value and deletion flag.
//
-// modify returns the size delta (-1, 0, +1).
+// Modify returns the size delta (-1, 0, +1).
// This method handles path traversal, node creation for new paths, and automatic
// purge/compress operations after deletions.
//
@@ -526,9 +562,10 @@ func (n *LiteNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
var zero V
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// record the nodes on the path to the deleted node, needed to purge
// and/or path compress nodes after the deletion of a prefix
@@ -536,16 +573,15 @@ func (n *LiteNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
// find the proper trie node to update prefix
for depth, octet := range octets {
- depth = depth & DepthMask // BCE
+ depth &= DepthMask // BCE
// push current node on stack for path recording
stack[depth] = n
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ // The current depth matches the prefix's stride count, meaning this is the final
+ // stride for this prefix. Insert or update it directly in this node's prefix table.
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
oldVal, existed := n.GetPrefix(idx)
newVal, del := cb(oldVal, existed)
@@ -585,7 +621,7 @@ func (n *LiteNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
}
// insert
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
n.InsertChild(octet, NewFringeNode(newVal))
} else {
n.InsertChild(octet, NewLeafNode(pfx, newVal))
@@ -644,7 +680,7 @@ func (n *LiteNode[V]) Modify(pfx netip.Prefix, cb func(val V, found bool) (_ V,
case *FringeNode[V]:
// update existing value if prefix is fringe
- if IsFringe(depth, pfx) {
+ if IsFringe(depth, pfxLen) {
newVal, del := cb(kid.Value, true)
if !del {
kid.Value = newVal
@@ -774,8 +810,8 @@ func (n *LiteNode[V]) EqualRec(o *LiteNode[V]) bool {
//
// It returns immediately if n is nil or empty. For each visited internal node
// it calls dump to write the node's representation, then iterates its child
-// addresses and recurses into children that implement nodeDumper[V] (internal
-// subnodes). The path slice and depth together represent the byte-wise path
+// addresses and recurses into children of type *LiteNode[V] (internal subnodes).
+// The path slice and depth together represent the byte-wise path
// from the root to the current node; depth is incremented for each recursion.
// The is4 flag controls IPv4/IPv6 formatting used by dump.
func (n *LiteNode[V]) DumpRec(w io.Writer, path StridePath, depth int, is4 bool) {
@@ -803,8 +839,8 @@ func (n *LiteNode[V]) dump(w io.Writer, path StridePath, depth int, is4 bool) {
bits := depth * strideLen
indent := strings.Repeat(".", depth)
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// node type with depth and octet path and bits.
fmt.Fprintf(w, "\n%s[%s] depth: %d path: [%s] / %d\n",
@@ -967,7 +1003,7 @@ func (n *LiteNode[V]) DumpString(octets []uint8, depth int, is4 bool) string {
// - stopNode: has children but no subnodes (nodes == 0)
// - halfNode: contains at least one leaf or fringe and also has subnodes, but
// no prefixes
-// - fullNode: has prefixes or leaves/fringes and also has subnodes
+// - fullNode: has prefixes and also has subnodes
// - pathNode: has subnodes only (no prefixes, leaves, or fringes)
//
// The order of these checks is significant to ensure the correct classification.
@@ -1024,7 +1060,7 @@ func (n *LiteNode[V]) Stats() (s StatsT) {
// It walks the node tree recursively and sums immediate counts (prefixes and
// child slots) plus the number of nodes, leaves, and fringe nodes in the
// subtree. If n is nil or empty, a zeroed stats is returned. The returned
-// stats.nodes includes the current node. The function will panic if a child
+// SubNodes count includes the current node. The function will panic if a child
// has an unexpected concrete type.
func (n *LiteNode[V]) StatsRec() (s StatsT) {
if n == nil || n.IsEmpty() {
@@ -1080,8 +1116,8 @@ func (n *LiteNode[V]) FprintRec(w io.Writer, parent TrieItem[V], pad string) err
return CmpPrefix(a.Cidr, b.Cidr)
})
- // printing values if V is not zero-sized
- printValues := !value.IsZST[V]()
+ // printing values if V is not the empty struct{}
+ printValues := !value.IsEmptyStruct[V]()
// for all direct item under this node ...
for i, item := range directItems {
@@ -1178,7 +1214,7 @@ func (n *LiteNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
path[depth] = addr
directItems = append(directItems, kid.DirectItemsRec(0, path, depth+1, is4)...)
- case *LeafNode[V]: // path-compressed child, stop's recursion for this child
+ case *LeafNode[V]: // path-compressed child, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1187,7 +1223,7 @@ func (n *LiteNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
}
directItems = append(directItems, item)
- case *FringeNode[V]: // path-compressed fringe, stop's recursion for this child
+ case *FringeNode[V]: // path-compressed fringe, stops recursion for this child
item := TrieItem[V]{
Node: nil,
Is4: is4,
@@ -1221,9 +1257,9 @@ func (n *LiteNode[V]) DirectItemsRec(parentIdx uint8, path StridePath, depth int
// The merge operation is destructive on the receiver n, but leaves the source node o unchanged.
//
// Returns the number of duplicate prefixes that were overwritten during merging.
-func (n *LiteNode[V]) UnionRec(cloneFn value.CloneFunc[V], o *LiteNode[V], depth int) (duplicates int) {
+func (n *LiteNode[V]) UnionRec(cloneFn func(V) V, o *LiteNode[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1254,9 +1290,9 @@ func (n *LiteNode[V]) UnionRec(cloneFn value.CloneFunc[V], o *LiteNode[V], depth
}
// UnionRecPersist is similar to unionRec but performs an immutable union of nodes.
-func (n *LiteNode[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *LiteNode[V], depth int) (duplicates int) {
+func (n *LiteNode[V]) UnionRecPersist(cloneFn func(V) V, o *LiteNode[V], depth int) (duplicates int) {
if cloneFn == nil {
- cloneFn = value.CopyVal
+ cloneFn = func(v V) V { return v }
}
buf := [256]uint8{}
@@ -1305,7 +1341,7 @@ func (n *LiteNode[V]) UnionRecPersist(cloneFn value.CloneFunc[V], o *LiteNode[V]
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *LiteNode[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *LiteNode[V]) handleMatrix(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*LiteNode[V])
@@ -1422,7 +1458,7 @@ func (n *LiteNode[V]) handleMatrix(cloneFn value.CloneFunc[V], thisExists bool,
// fringe, node <-- insert new node, push this fringe down, union rec-descent
// fringe, leaf <-- insert new node, push this fringe down, insert other leaf at depth+1
// fringe, fringe <-- just overwrite value
-func (n *LiteNode[V]) handleMatrixPersist(cloneFn value.CloneFunc[V], thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
+func (n *LiteNode[V]) handleMatrixPersist(cloneFn func(V) V, thisExists bool, thisChild, otherChild any, addr uint8, depth int) int {
// Do ALL type assertions upfront - reduces line noise
var (
thisNode, thisIsNode = thisChild.(*LiteNode[V])
@@ -1654,9 +1690,7 @@ func (n *LiteNode[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield f
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, childAddr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1691,9 +1725,7 @@ func (n *LiteNode[V]) AllRecSorted(path StridePath, depth int, is4 bool, yield f
}
case *FringeNode[V]:
fringePfx := CidrForFringe(path[:], depth, is4, addr)
- // callback for this fringe
if !yield(fringePfx, kid.Value) {
- // early exit
return false
}
@@ -1879,9 +1911,10 @@ func (n *LiteNode[V]) EachSubnet(octets []byte, depth int, is4 bool, pfxIdx uint
// the iteration early.
func (n *LiteNode[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// stack of the traversed nodes for reverse ordering of supernets
stack := [MaxTreeDepth]*LiteNode[V]{}
@@ -1894,7 +1927,7 @@ func (n *LiteNode[V]) Supernets(pfx netip.Prefix, yield func(netip.Prefix, V) bo
LOOP:
for depth, octet = range octets {
// stepped one past the last stride of interest; back up to last and exit
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
depth--
break
}
@@ -1955,11 +1988,10 @@ LOOP:
// all others are just host routes
var idx uint8
octet = octets[depth]
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx = art.PfxToIdx(octet, lastBits)
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
+ if depth == strideCount {
+ idx = art.PfxToIdx(octet, modBits)
} else {
idx = art.OctetToIdx(octet)
}
@@ -1996,17 +2028,18 @@ LOOP:
func (n *LiteNode[V]) Subnets(pfx netip.Prefix, yield func(netip.Prefix, V) bool) {
// values derived from pfx
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
// find the trie node
for depth, octet := range octets {
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4/16),
+ // Last “octet” from prefix
+ // Note: For /32 and /128, depth never reaches strideCount (4/16),
// so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx := art.PfxToIdx(octet, lastBits)
+ if depth == strideCount {
+ idx := art.PfxToIdx(octet, modBits)
n.EachSubnet(octets, depth, is4, idx, yield)
return
}
@@ -2124,7 +2157,7 @@ func (n *LiteNode[V]) Overlaps(o *LiteNode[V], depth int) bool {
// OverlapsRoutes compares the prefix sets of two nodes (n and o).
//
// It first checks for direct bitset intersection (identical indices),
-// then walks both prefix sets using lpmTest to detect if any
+// then walks both prefix sets using the Contains method to detect if any
// of the n-prefixes is contained in o, or vice versa.
func (n *LiteNode[V]) OverlapsRoutes(o *LiteNode[V]) bool {
// some prefixes are identical, trivial overlap
@@ -2267,19 +2300,20 @@ func (n *LiteNode[V]) OverlapsSameChildren(o *LiteNode[V], depth int) bool {
// trie traversal across varying prefix lengths and compression levels.
func (n *LiteNode[V]) OverlapsPrefixAtDepth(pfx netip.Prefix, depth int) bool {
ip := pfx.Addr()
+ pfxLen := pfx.Bits()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := DivMod8(pfxLen)
for ; depth < len(octets); depth++ {
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
break
}
octet := octets[depth]
// full octet path in node trie, check overlap with last prefix octet
- if depth == lastOctetPlusOne {
- return n.OverlapsIdx(art.PfxToIdx(octet, lastBits))
+ if depth == strideCount {
+ return n.OverlapsIdx(art.PfxToIdx(octet, modBits))
}
// test if any route overlaps prefix´ so far
diff --git a/vendor/github.com/gaissmai/bart/internal/nodes/nodebasics.go b/vendor/github.com/gaissmai/bart/internal/nodes/nodebasics.go
index a2f1088dd8..2439de1535 100644
--- a/vendor/github.com/gaissmai/bart/internal/nodes/nodebasics.go
+++ b/vendor/github.com/gaissmai/bart/internal/nodes/nodebasics.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package nodes
@@ -11,7 +11,6 @@ import (
"strings"
"github.com/gaissmai/bart/internal/art"
- "github.com/gaissmai/bart/internal/value"
)
// strideLen represents the byte stride length for the multibit trie.
@@ -159,41 +158,23 @@ func NewFringeNode[V any](val V) *FringeNode[V] {
return &FringeNode[V]{Value: val}
}
-// IsFringe determines whether a prefix qualifies as a "fringe node" -
-// that is, a special kind of path-compressed leaf inserted at the final
-// possible trie level (depth == lastOctet).
+// IsFringe determines whether a prefix qualifies as a "FringeNode".
+// Only prefixes that are stride-aligned (i.e., /8, /16, ..., /128)
+// can be fringe-compressed. If these prefixes are inserted at a position
+// where depth == (strideCount-1), they are treated as FringeNodes;
+// at positions where depth < (strideCount-1), they are treated as LeafNodes.
//
-// Both "leaves" and "fringes" are path-compressed terminal entries;
-// the distinction lies in their position within the trie:
+// Example for a stride-aligned prefix like 192.168.1.0/24 (strideCount = 3, modBits = 0):
//
-// - A leaf is inserted at any intermediate level if no further stride
-// boundary matches (depth < lastOctet).
-//
-// - A fringe is inserted at the last possible stride level
-// (depth == lastOctet) before a prefix would otherwise land
-// as a direct prefix (depth == lastOctet+1).
-//
-// Special property:
-// - A fringe acts as a default route for all downstream bit patterns
-// extending beyond its prefix.
-//
-// Examples:
-//
-// e.g. prefix is addr/8, or addr/16, or ... addr/128
-// depth < lastOctet : a leaf, path-compressed
-// depth == lastOctet : a fringe, path-compressed
-// depth == lastOctet+1: a prefix with octet/pfx == 0/0 => idx == 1, a strides default route
-//
-// Logic:
-// - A prefix qualifies as a fringe if:
-// depth == lastOctet && lastBits == 0
-// (i.e., aligned on stride boundary, /8, /16, ... /128 bits)
-func IsFringe(depth int, pfx netip.Prefix) bool {
- lastOctetPlusOne, lastBits := LastOctetPlusOneAndLastBits(pfx)
- return depth == lastOctetPlusOne-1 && lastBits == 0
+// depth = 3, depth == strideCount : A direct prefix with 0/0 (default route for subtrie).
+// depth = 2, depth == (strideCount-1) : A path-compressed fringe.
+// depth < 2, depth < (strideCount-1) : A path-compressed leaf.
+func IsFringe(depth int, pfxLen int) bool {
+ strideCount, modBits := DivMod8(pfxLen)
+ return depth == strideCount-1 && modBits == 0
}
-// cmpIndexRank, sort indexes in prefix sort order.
+// CmpIndexRank, sort indexes in prefix sort order.
func CmpIndexRank(aIdx, bIdx uint8) int {
// convert idx [1..255] to prefix
aOctet, aBits := art.IdxToPfx(aIdx)
@@ -218,7 +199,7 @@ func CmpIndexRank(aIdx, bIdx uint8) int {
//
// Returns the reconstructed netip.Prefix.
func CidrFromPath(path StridePath, depth int, is4 bool, idx uint8) netip.Prefix {
- depth = depth & DepthMask // BCE
+ depth &= DepthMask // BCE
// retrieve the last octet and pfxLen
octet, pfxLen := art.IdxToPfx(idx)
@@ -247,21 +228,21 @@ func CidrFromPath(path StridePath, depth int, is4 bool, idx uint8) netip.Prefix
// CidrForFringe reconstructs a CIDR prefix for a fringe node from the traversal path.
// Since fringe nodes don't store their prefix explicitly, it's derived entirely
-// from the node's position in the trie.
+// from the node's position in the trie and its final byte value.
//
// Parameters:
-// - octets: The path of octets leading to the fringe
-// - depth: Current depth in the trie
-// - is4: True for IPv4 processing, false for IPv6
-// - lastOctet: The final octet where the fringe is located
+// - octets: The path of previous bytes leading up to the fringe.
+// - depth: Current depth in the trie (which equals strideCount - 1).
+// - is4: True for IPv4 processing, false for IPv6.
+// - fringeByte: The actual 8-bit value (0-255) of the prefix at this final stride.
//
// Returns the reconstructed netip.Prefix for the fringe.
-func CidrForFringe(octets []byte, depth int, is4 bool, lastOctet uint8) netip.Prefix {
- depth = depth & DepthMask // BCE
+func CidrForFringe(octets []byte, depth int, is4 bool, fringeByte uint8) netip.Prefix {
+ depth &= DepthMask // BCE
var path StridePath
copy(path[:], octets)
- path[depth] = lastOctet
+ path[depth] = fringeByte
// canonicalize, fringe bit boundaries are always a multiple of a byte
clear(path[depth+1:])
@@ -274,7 +255,7 @@ func CidrForFringe(octets []byte, depth int, is4 bool, lastOctet uint8) netip.Pr
ip = netip.AddrFrom16(path)
}
- // it's a fringe, bits are always /8, /16, /24, ...
+ // it's a fringe, bits are always aligned on stride boundaries (/8, /16, /24, ...)
bits := (depth + 1) << 3
// PrefixFrom does not allocate and does not mask off the host bits of ip.
@@ -282,31 +263,28 @@ func CidrForFringe(octets []byte, depth int, is4 bool, lastOctet uint8) netip.Pr
return netip.PrefixFrom(ip, bits)
}
-// LastOctetPlusOneAndLastBits returns the count of full 8‑bit strides (bits/8)
-// and the leftover bits in the final stride (bits%8) for pfx.
+// DivMod8 returns the count of full 8‑bit strides (bits/8)
+// and the remaining bits in the final stride (bits%8) for pfxLen.
//
-// lastOctetPlusOne is the count of full 8‑bit strides (bits/8).
-// lastBits is the remaining bit count in the final stride (bits%8),
-//
-// ATTENTION: Split the IP prefixes at 8bit borders, count from 0.
+// ATTENTION: Split the IP prefixes at 8-bit borders, count from 0.
//
// /7, /15, /23, /31, ..., /127
//
// BitPos: [0-7],[8-15],[16-23],[24-31],[32]
// BitPos: [0-7],[8-15],[16-23],[24-31],[32-39],[40-47],[48-55],[56-63],...,[120-127],[128]
//
-// 0.0.0.0/0 => lastOctetPlusOne: 0, lastBits: 0 (default route)
-// 0.0.0.0/7 => lastOctetPlusOne: 0, lastBits: 7
-// 0.0.0.0/8 => lastOctetPlusOne: 1, lastBits: 0 (possible fringe)
-// 10.0.0.0/8 => lastOctetPlusOne: 1, lastBits: 0 (possible fringe)
-// 10.0.0.0/22 => lastOctetPlusOne: 2, lastBits: 6
-// 10.0.0.0/29 => lastOctetPlusOne: 3, lastBits: 5
-// 10.0.0.0/32 => lastOctetPlusOne: 4, lastBits: 0 (possible fringe)
+// 0.0.0.0/0 => strideCount: 0, modBits: 0 (default route)
+// 0.0.0.0/7 => strideCount: 0, modBits: 7
+// 0.0.0.0/8 => strideCount: 1, modBits: 0 (fringe candidate)
+// 10.0.0.0/8 => strideCount: 1, modBits: 0 (fringe candidate)
+// 10.0.0.0/22 => strideCount: 2, modBits: 6
+// 10.0.0.0/29 => strideCount: 3, modBits: 5
+// 10.0.0.0/32 => strideCount: 4, modBits: 0 (fringe candidate)
//
-// ::/0 => lastOctetPlusOne: 0, lastBits: 0 (default route)
-// ::1/128 => lastOctetPlusOne: 16, lastBits: 0 (possible fringe)
-// 2001:db8::/42 => lastOctetPlusOne: 5, lastBits: 2
-// 2001:db8::/56 => lastOctetPlusOne: 7, lastBits: 0 (possible fringe)
+// ::/0 => strideCount: 0, modBits: 0 (default route)
+// ::1/128 => strideCount: 16, modBits: 0 (fringe candidate)
+// 2001:db8::/42 => strideCount: 5, modBits: 2
+// 2001:db8::/56 => strideCount: 7, modBits: 0 (fringe candidate)
//
// /32 and /128 prefixes are special, they never form a new node,
// At the end of the trie (IPv4: depth 4, IPv6: depth 16) they are always
@@ -315,27 +293,25 @@ func CidrForFringe(octets []byte, depth int, is4 bool, lastOctet uint8) netip.Pr
// We are not splitting at /8, /16, ..., because this would mean that the
// first node would have 512 prefixes, 9 bits from [0-8]. All remaining nodes
// would then only have 8 bits from [9-16], [17-24], [25..32], ...
-// but the algorithm would then require a variable length bitset.
+// but the algorithm would then require a variable length bitset
+// or imply a double-sized bitset.
//
// If you can commit to a fixed size of [4]uint64, then the algorithm is
// much faster due to modern CPUs.
//
// Perhaps a future Go version that supports SIMD instructions for the [4]uint64 vectors
// will make the algorithm even faster on suitable hardware.
-func LastOctetPlusOneAndLastBits(pfx netip.Prefix) (lastOctetPlusOne int, lastBits uint8) {
- // lastOctetPlusOne: range from 0..4 or 0..16 !ATTENTION: not 0..3 or 0..15
- // lastBits: range from 0..7
- bits := pfx.Bits()
-
- //nolint:gosec // G115: narrowing conversion is safe here (bits in [0..128])
- return bits >> 3, uint8(bits & 7)
+func DivMod8(pfxLen int) (strideCount int, modBits uint8) {
+ // strideCount: range from 0..4 or 0..16
+ // modBits: range from 0..7
+ return pfxLen >> 3, uint8(pfxLen & 7)
}
// CloneLeaf creates and returns a copy of the leafNode receiver.
// If cloneFn is nil, the value is copied directly without modification.
// Otherwise, cloneFn is applied to the value for deep cloning.
// The prefix field is always copied as is.
-func (l *LeafNode[V]) CloneLeaf(cloneFn value.CloneFunc[V]) *LeafNode[V] {
+func (l *LeafNode[V]) CloneLeaf(cloneFn func(V) V) *LeafNode[V] {
if l == nil {
return nil
}
@@ -346,10 +322,10 @@ func (l *LeafNode[V]) CloneLeaf(cloneFn value.CloneFunc[V]) *LeafNode[V] {
return &LeafNode[V]{Prefix: l.Prefix, Value: cloneFn(l.Value)}
}
-// cloneFringe creates and returns a copy of the fringeNode receiver.
+// CloneFringe creates and returns a copy of the FringeNode receiver.
// If cloneFn is nil, the value is copied directly without modification.
// Otherwise, cloneFn is applied to the value for deep cloning.
-func (l *FringeNode[V]) CloneFringe(cloneFn value.CloneFunc[V]) *FringeNode[V] {
+func (l *FringeNode[V]) CloneFringe(cloneFn func(V) V) *FringeNode[V] {
if l == nil {
return nil
}
diff --git a/vendor/github.com/gaissmai/bart/internal/sparse/array256.go b/vendor/github.com/gaissmai/bart/internal/sparse/array256.go
index 76a6e722a6..5c215cf305 100644
--- a/vendor/github.com/gaissmai/bart/internal/sparse/array256.go
+++ b/vendor/github.com/gaissmai/bart/internal/sparse/array256.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
// Package sparse provides a compact and efficient sparse array
@@ -51,12 +51,12 @@ type Array256[T any] struct {
// Set panics. The bitset is internally coupled with Items[].
// Use InsertAt to add or overwrite at index i.
-func (a *Array256[T]) Set(uint) {
+func (a *Array256[T]) Set(uint8) {
panic("forbidden, use InsertAt")
}
// Clear panics. The bitset is internally coupled with Items[].
-func (a *Array256[T]) Clear(uint) {
+func (a *Array256[T]) Clear(uint8) {
panic("forbidden, use DeleteAt")
}
@@ -72,7 +72,7 @@ func (a *Array256[T]) Clear(uint) {
// ⬆
//
// BitSet256.Test(5): true
-// BitSet256.Rank(5): 2,
+// BitSet256.Rank(5): 2
func (a *Array256[T]) Get(i uint8) (value T, ok bool) {
if a.Test(i) {
return a.Items[a.Rank(i)-1], true
@@ -108,24 +108,37 @@ func (a *Array256[T]) Copy() *Array256[T] {
return c
}
-// InsertAt adds the value to the index i. If a value already exists there,
-// it is overwritten and true is returned.
+// InsertAt inserts or overwrites the value at sparse index i.
//
-// Otherwise, the value is inserted, the bit is marked, and false returned.
-func (a *Array256[T]) InsertAt(i uint8, value T) (exists bool) {
- // slot exists, overwrite value
+// If the slot at i already exists, its value is overwritten in-place and
+// (rank0, true) is returned, where rank0 = Rank(i)-1 is the 0-based index
+// into Items[].
+//
+// If the slot is new, the bit for i is set, the value is inserted into Items[]
+// at the correct packed position, and (rank0, false) is returned.
+//
+// rank0 can be cached by the caller to directly access Items[rank0]
+// without a second Rank() call.
+func (a *Array256[T]) InsertAt(i uint8, value T) (rank0 int, exists bool) {
+
+ // slot exists, just overwrite value
if a.Test(i) {
- a.Items[a.Rank(i)-1] = value
- return true
+ rank0 = a.Rank(i) - 1
+ a.Items[rank0] = value
+ return rank0, true
}
+ // Since i is not set yet, Rank(i) before Set(i) is exactly
+ // the index where the new item should be inserted (equivalent to Rank(i)-1 after Set(i)).
+ rank0 = a.Rank(i)
+
// new, insert into bitset ...
a.BitSet256.Set(i)
- // ... and slice
- a.insertItem(a.Rank(i)-1, value)
+ // ... and insert value into slice
+ a.insertItem(rank0, value)
- return false
+ return rank0, false
}
// DeleteAt removes the value at index i from the sparse array,
@@ -154,7 +167,7 @@ func (a *Array256[T]) DeleteAt(i uint8) (value T, exists bool) {
// shifting all following elements one position to the right to make space.
//
// This method must be called with the correct insertion index - that is,
-// the rank-0 value of the corresponding bit index i in BitSet256 once it's set.
+// the rank-0 value of the corresponding bit index i in BitSet256 (calculated before Set(i)).
//
// The slice will be extended by one element. If the capacity allows, this is done
// without reallocation (fast path); otherwise slice growth occurs (slow path).
diff --git a/vendor/github.com/gaissmai/bart/internal/tests/golden/table.go b/vendor/github.com/gaissmai/bart/internal/tests/golden/table.go
index 421287e549..727b3a9b65 100644
--- a/vendor/github.com/gaissmai/bart/internal/tests/golden/table.go
+++ b/vendor/github.com/gaissmai/bart/internal/tests/golden/table.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package golden
diff --git a/vendor/github.com/gaissmai/bart/internal/tests/random/random.go b/vendor/github.com/gaissmai/bart/internal/tests/random/random.go
index 5dcd32dbd7..7ee67a65d8 100644
--- a/vendor/github.com/gaissmai/bart/internal/tests/random/random.go
+++ b/vendor/github.com/gaissmai/bart/internal/tests/random/random.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package random
@@ -41,6 +41,7 @@ func Prefix6(prng *rand.Rand) netip.Prefix {
func IP4(prng *rand.Rand) netip.Addr {
var b [4]byte
for i := range b {
+ //nolint:gosec // G115: integer overflow conversion uint -> byte
b[i] = byte(prng.UintN(256))
}
return netip.AddrFrom4(b)
@@ -49,6 +50,7 @@ func IP4(prng *rand.Rand) netip.Addr {
func IP6(prng *rand.Rand) netip.Addr {
var b [16]byte
for i := range b {
+ //nolint:gosec // G115: integer overflow conversion uint -> byte
b[i] = byte(prng.UintN(256))
}
return netip.AddrFrom16(b)
diff --git a/vendor/github.com/gaissmai/bart/internal/value/value.go b/vendor/github.com/gaissmai/bart/internal/value/value.go
index 8fa7bd0b7a..9ebe1ae90a 100644
--- a/vendor/github.com/gaissmai/bart/internal/value/value.go
+++ b/vendor/github.com/gaissmai/bart/internal/value/value.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
// Package value provides runtime utilities for working with generic type
@@ -6,134 +6,72 @@
//
// The package offers three main categories of utilities:
//
-// # Zero-Sized Type (ZST) Detection
+// # V as type struct{} Detection
//
-// IsZST[V] detects whether a type parameter V is a zero-sized type (such as
-// struct{} or [0]byte). This serves two purposes:
-// - Runtime validation: Fast[V] cannot work correctly with zero-sized types
-// and must reject them. PanicOnZST enables a safety check that panics
-// during Fast.Insert and Fast.InsertPersist operations.
-// - Debug output clarity: Zero-sized types carry no information in their
-// values. Omitting them from dumps and prints reduces line noise and
-// improves readability.
+// IsEmptyStruct[V] detects whether a type parameter V is a `struct{}`. These
+// types carry no information in their values. Omitting them from dumps
+// and prints reduces line noise and improves readability.
//
// # Value Equality
//
-// The Equaler[V] interface and Equal function enable custom equality logic
-// for payload values. When V implements Equaler[V], the Equal function uses
-// that implementation, avoiding the potentially expensive reflect.DeepEqual.
+// The [Equal] function enables custom equality logic for payload values.
+// When V implements an `Equal(V) bool` method, [Equal] uses that implementation,
+// avoiding the potentially expensive [reflect.DeepEqual] fallback.
//
// # Value Cloning
//
-// The Cloner[V] interface and associated functions (CloneFnFactory, CloneVal,
-// CopyVal) support deep copying of payload values for persistent operations.
-// When V implements Cloner[V], bart methods like InsertPersist, DeletePersist,
-// and UnionPersist use the Clone method to create independent copies.
+// The [CloneFnFactory] supports copying of payload values for persistent
+// operations. When V implements a `Clone() V` method,
+// bart methods like InsertPersist, DeletePersist, and UnionPersist use the
+// generated clone function to create independent copies.
//
// This is an internal package used by the bart data structure implementation.
package value
-import (
- "fmt"
- "reflect"
-)
-
-// IsZST reports whether type V is a zero-sized type (ZST).
-//
-// Zero-sized types such as struct{}, [0]byte, or structs/arrays with no fields
-// occupy no memory. The Go runtime optimizes allocations of ZSTs by returning
-// pointers to the same memory address (typically runtime.zerobase).
-//
-// This function exploits that optimization: it allocates two instances of V
-// and compares their addresses. If the addresses are equal, V must be a ZST,
-// since distinct non-zero-sized allocations would have different addresses.
-//
-// The helper escapeToHeap ensures both allocations reach the heap and prevents
-// the compiler from proving address equality at compile time, which would
-// invalidate the runtime check.
-func IsZST[V any]() bool {
- a, b := escapeToHeap[V]()
- return a == b
+// IsEmptyStruct reports whether type V is the unnamed empty struct type `struct{}`.
+func IsEmptyStruct[V any]() bool {
+ var zero V
+ _, ok := any(zero).(struct{})
+ return ok
}
-// escapeToHeap forces two allocations of type V to escape to the heap.
+// Equal compares two values of type V for equality.
//
-// The go:noinline directive is critical: it prevents the compiler from inlining
-// this function and optimizing away the allocations or proving that a == b at
-// compile time. Without it, the compiler could elide one allocation or determine
-// the result statically, breaking the ZST detection heuristic.
+// If V implements an `Equal(V) bool` method, its custom equality logic is used.
+// Otherwise, values are compared directly using the == operator.
//
-//go:noinline
-func escapeToHeap[V any]() (*V, *V) {
- return new(V), new(V)
-}
-
-// PanicOnZST panics if V is a zero sized type.
-// bart.Fast must reject zero-sized types as payload.
-func PanicOnZST[V any]() {
- if IsZST[V]() {
- panic(fmt.Errorf("%T is a zero-sized type, not allowed as payload for bart.Fast", *new(V)))
- }
-}
-
-// Equaler is a generic interface for types that can decide their own
-// equality logic. It can be used to override the potentially expensive
-// default comparison with [reflect.DeepEqual].
-type Equaler[V any] interface {
- Equal(other V) bool
-}
-
-// Equal compares two values of type V for equality.
-// If V implements Equaler[V], that custom equality method is used,
-// avoiding the potentially expensive reflect.DeepEqual.
-// Otherwise, reflect.DeepEqual is used as a fallback.
+// If V is not comparable at runtime (such as a slice or map without an Equal
+// method), a runtime panic will occur.
+//
+// Note: If V implements Equal(V) bool with a pointer receiver, the Equal
+// method should handle nil receivers gracefully.
func Equal[V any](v1, v2 V) bool {
- // you can't assert directly on a type parameter
- if v1, ok := any(v1).(Equaler[V]); ok {
- return v1.Equal(v2)
+ if eq, ok := any(v1).(interface{ Equal(V) bool }); ok {
+ return eq.Equal(v2)
}
- // fallback
- return reflect.DeepEqual(v1, v2)
-}
-// Cloner is an interface that enables deep cloning of values of type V.
-// If a value implements Cloner[V], Table methods such as InsertPersist,
-// ModifyPersist, DeletePersist, UnionPersist, Union and Clone will use
-// its Clone method to perform deep copies.
-type Cloner[V any] interface {
- Clone() V
+ return any(v1) == any(v2)
}
-// CloneFunc is a type definition for a function that takes a value of type V
-// and returns the (possibly cloned) value of type V.
-type CloneFunc[V any] func(V) V
-
-// CloneFnFactory returns a CloneFunc.
-// If V implements Cloner[V], the returned function should perform
-// a deep copy using Clone(), otherwise it returns nil.
-func CloneFnFactory[V any]() CloneFunc[V] {
+// CloneFnFactory returns a function that takes a value of type V and returns
+// a copy by calling its `Clone` method.
+//
+// If V does not implement a `Clone() V` method, it returns nil.
+//
+// Note: If V implements `Clone() V` with a pointer receiver, the `Clone`
+// method should handle nil receivers gracefully.
+func CloneFnFactory[V any]() func(V) V {
var zero V
- // you can't assert directly on a type parameter
- if _, ok := any(zero).(Cloner[V]); ok {
- return CloneVal[V]
- }
- return nil
-}
-// CloneVal returns a deep clone of val by calling Clone when
-// val implements Cloner[V]. If val does not implement
-// Cloner[V] or the Cloner receiver is nil (val is a nil pointer),
-// CloneVal returns val unchanged.
-func CloneVal[V any](val V) V {
- // you can't assert directly on a type parameter
- c, ok := any(val).(Cloner[V])
- if !ok || c == nil {
- return val
+ // Safely check if V implements the clone method using an inline interface.
+ if _, ok := any(zero).(interface{ Clone() V }); ok {
+ // Return an anonymous closure directly.
+ // Since we already proved V implements the interface above,
+ // the direct type assertion here is guaranteed to succeed.
+ return func(val V) V {
+ return any(val).(interface{ Clone() V }).Clone()
+ }
}
- return c.Clone()
-}
-// CopyVal just copies the value of any type V.
-func CopyVal[V any](val V) V {
- return val
+ return nil
}
diff --git a/vendor/github.com/gaissmai/bart/lite.go b/vendor/github.com/gaissmai/bart/lite.go
index a266c558af..92ff17a8c8 100644
--- a/vendor/github.com/gaissmai/bart/lite.go
+++ b/vendor/github.com/gaissmai/bart/lite.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package bart
@@ -21,6 +21,7 @@ import (
// The zero value is ready to use.
//
// A Lite table must not be copied by value; always pass by pointer.
+// Nil pointers as receivers or arguments are forbidden and will panic.
//
// Performance note: Do not pass IPv4-in-IPv6 addresses (e.g., ::ffff:192.0.2.1)
// as input. The methods do not perform automatic unmapping to avoid unnecessary
@@ -73,7 +74,7 @@ func (l *Lite) LookupPrefix(pfx netip.Prefix) bool {
// match any address in the provided prefix range.
//
// This is functionally identical to LookupPrefix but returns the
-// matching prefix (lpmPfx) itself.
+// matching LPM prefix itself.
//
// This method is slower than LookupPrefix and should only be used if the
// matching lpm entry is also required for other reasons.
@@ -165,11 +166,12 @@ func (l *Lite) Modify(pfx netip.Prefix, cb func(exists bool) (del bool)) {
// ModifyPersist is similar to Modify but the receiver isn't modified and
// a new *Lite is returned.
func (l *Lite) ModifyPersist(pfx netip.Prefix, cb func(exists bool) (del bool)) *Lite {
- wrappedFn := func(_ struct{}, exists bool) (_ struct{}, del bool) {
+ // wrap callback to match the signature of liteTable.ModifyPersist
+ cbWrapper := func(_ struct{}, exists bool) (_ struct{}, del bool) {
return struct{}{}, cb(exists)
}
- lp := l.liteTable.ModifyPersist(pfx, wrappedFn)
+ lp := l.liteTable.ModifyPersist(pfx, cbWrapper)
//nolint:govet // copy of *lp is here by intention
return &Lite{*lp}
}
@@ -185,9 +187,6 @@ func dropSeq2[V any](seq2 iter.Seq2[netip.Prefix, V]) iter.Seq[netip.Prefix] {
// Clone returns a copy of the routing table.
func (l *Lite) Clone() *Lite {
- if l == nil {
- return nil
- }
return &Lite{*l.liteTable.Clone()}
}
@@ -195,112 +194,58 @@ func (l *Lite) Clone() *Lite {
//
// All prefixes from the other table (o) are inserted into the receiver.
func (l *Lite) Union(o *Lite) {
- if o == nil {
- return
- }
l.liteTable.Union(&o.liteTable)
}
// UnionPersist is similar to [Union] but the receiver isn't modified.
//
// All nodes touched during union are cloned and a new *Lite is returned.
-// If o is nil or empty, no nodes are touched and the receiver may be
+// If o is empty, no nodes are touched and the receiver may be
// returned unchanged.
func (l *Lite) UnionPersist(o *Lite) *Lite {
- if o == nil || (o.size4 == 0 && o.size6 == 0) {
+ lp := l.liteTable.UnionPersist(&o.liteTable)
+ if lp == &l.liteTable {
return l
}
- lp := l.liteTable.UnionPersist(&o.liteTable)
//nolint:govet // copy of *lp is here by intention
return &Lite{*lp}
}
// All returns an iterator over all prefixes in the table.
//
-// The entries from both IPv4 and IPv6 subtries are yielded using an internal recursive traversal.
-// The iteration order is unspecified and may vary between calls; for a stable order, use AllSorted.
-//
-// You can use All directly in a for-range loop without providing a yield function.
-// The Go compiler automatically synthesizes the yield callback for you:
-//
-// for prefix := range t.All() {
-// fmt.Println(prefix)
-// }
-//
-// Under the hood, the loop body is passed as a yield function to the iterator.
-// If you break or return from the loop, iteration stops early as expected.
+// The iteration order is unspecified and may vary between calls; for a stable order,
+// use [Lite.AllSorted].
//
-// IMPORTANT: Modifying or deleting entries during iteration is not allowed,
+// IMPORTANT: Modifying the table during iteration is not allowed,
// as this would interfere with the internal traversal and may corrupt or
-// prematurely terminate the iteration. If mutation of the table during
-// traversal is required use persistent table methods, e.g.
-// pl := l
-// for pfx := range l.All() {
-// if cond(pfx) {
-// pl = pl.DeletePersist(pfx)
-// }
-// }
-
+// prematurely terminate the iteration.
func (l *Lite) All() iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.All())
}
// All4 is like [Lite.All] but only for the v4 routing table.
func (l *Lite) All4() iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.All4())
}
// All6 is like [Lite.All] but only for the v6 routing table.
func (l *Lite) All6() iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.All6())
}
-// AllSorted returns an iterator over all prefixes in the table,
-// ordered in canonical CIDR prefix sort order.
-//
-// This can be used directly with a for-range loop;
-// the Go compiler provides the yield function implicitly.
-//
-// for prefix := range t.AllSorted() {
-// fmt.Println(prefix)
-// }
-//
-// The traversal is stable and predictable across calls.
-// Iteration stops early if you break out of the loop.
-//
-// IMPORTANT: Deleting entries during iteration is not allowed,
-// as this would interfere with the internal traversal and may corrupt or
-// prematurely terminate the iteration. If mutation of the table during
-// traversal is required use persistent table methods.
+// AllSorted is like [Lite.All] but the iteration is ordered in canonical
+// CIDR prefix sort order.
func (l *Lite) AllSorted() iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.AllSorted())
}
// AllSorted4 is like [Lite.AllSorted] but only for the v4 routing table.
func (l *Lite) AllSorted4() iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.AllSorted4())
}
// AllSorted6 is like [Lite.AllSorted] but only for the v6 routing table.
func (l *Lite) AllSorted6() iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.AllSorted6())
}
@@ -318,9 +263,6 @@ func (l *Lite) AllSorted6() iter.Seq[netip.Prefix] {
// The iteration can be stopped early by breaking from the range loop.
// Returns an empty iterator if the prefix is invalid.
func (l *Lite) Subnets(pfx netip.Prefix) iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.Subnets(pfx))
}
@@ -345,9 +287,6 @@ func (l *Lite) Subnets(pfx netip.Prefix) iter.Seq[netip.Prefix] {
// fmt.Println("Matched covering route:", supernet)
// }
func (l *Lite) Supernets(pfx netip.Prefix) iter.Seq[netip.Prefix] {
- if l == nil {
- return func(func(netip.Prefix) bool) {}
- }
return dropSeq2(l.liteTable.Supernets(pfx))
}
@@ -367,25 +306,16 @@ func (l *Lite) Supernets(pfx netip.Prefix) iter.Seq[netip.Prefix] {
// It is intentionally not nil-receiver safe: calling with a nil
// receiver will panic by design.
func (l *Lite) Overlaps(o *Lite) bool {
- if o == nil {
- return false
- }
return l.liteTable.Overlaps(&o.liteTable)
}
// Overlaps4 is like [Lite.Overlaps] but for the v4 routing table only.
func (l *Lite) Overlaps4(o *Lite) bool {
- if o == nil {
- return false
- }
return l.liteTable.Overlaps4(&o.liteTable)
}
// Overlaps6 is like [Lite.Overlaps] but for the v6 routing table only.
func (l *Lite) Overlaps6(o *Lite) bool {
- if o == nil {
- return false
- }
return l.liteTable.Overlaps6(&o.liteTable)
}
@@ -395,27 +325,18 @@ func (l *Lite) Overlaps6(o *Lite) bool {
//
// Note: Lite has no payload values, so this only checks structural equality.
func (l *Lite) Equal(o *Lite) bool {
- if o == nil || l.size4 != o.size4 || l.size6 != o.size6 {
- return false
- }
return l.liteTable.Equal(&o.liteTable)
}
// DumpList4 dumps the ipv4 tree into a list of roots and their subnets.
// It can be used to analyze the tree or build the text or JSON serialization.
func (l *Lite) DumpList4() []DumpListNode[struct{}] {
- if l == nil {
- return nil
- }
return l.liteTable.DumpList4()
}
// DumpList6 dumps the ipv6 tree into a list of roots and their subnets.
// It can be used to analyze the tree or build custom JSON representation.
func (l *Lite) DumpList6() []DumpListNode[struct{}] {
- if l == nil {
- return nil
- }
return l.liteTable.DumpList6()
}
@@ -442,27 +363,18 @@ func (l *Lite) DumpList6() []DumpListNode[struct{}] {
// │ └─ 2001:db8::/32 (V)
// └─ fe80::/10 (V)
func (l *Lite) Fprint(w io.Writer) error {
- if l == nil {
- return nil
- }
return l.liteTable.Fprint(w)
}
// MarshalJSON dumps the table into two sorted lists: for ipv4 and ipv6.
// Every root and subnet is an array, not a map, because the order matters.
func (l *Lite) MarshalJSON() ([]byte, error) {
- if l == nil {
- return []byte("null"), nil
- }
return l.liteTable.MarshalJSON()
}
// MarshalText implements the [encoding.TextMarshaler] interface,
// just a wrapper for [liteTable.Fprint].
func (l *Lite) MarshalText() ([]byte, error) {
- if l == nil {
- return []byte{}, nil
- }
return l.liteTable.MarshalText()
}
@@ -631,7 +543,7 @@ func (l *liteTable[V]) LookupPrefix(pfx netip.Prefix) (val V, exists bool) {
// match any address in the provided prefix range.
//
// This is functionally identical to LookupPrefix but additionally returns the
-// matching prefix (lpmPfx) itself along with the value.
+// matching LPM prefix itself along with the value.
//
// This method is slower than LookupPrefix and should only be used if the
// matching lpm entry is also required for other reasons.
@@ -656,10 +568,10 @@ func (l *liteTable[V]) lookupPrefixLPM(pfx netip.Prefix, withLPM bool) (lpmPfx n
pfx = pfx.Masked()
ip := pfx.Addr()
- bits := pfx.Bits()
+ pfxLen := pfx.Bits()
is4 := ip.Is4()
octets := ip.AsSlice()
- lastOctetPlusOne, lastBits := nodes.LastOctetPlusOneAndLastBits(pfx)
+ strideCount, modBits := nodes.DivMod8(pfxLen)
n := l.rootNodeByVersion(is4)
@@ -672,10 +584,10 @@ func (l *liteTable[V]) lookupPrefixLPM(pfx netip.Prefix, withLPM bool) (lpmPfx n
LOOP:
// find the last node on the octets path in the trie,
for depth, octet = range octets {
- depth = depth & nodes.DepthMask // BCE
+ depth &= nodes.DepthMask // BCE
// stepped one past the last stride of interest; back up to last and break
- if depth > lastOctetPlusOne {
+ if depth > strideCount {
depth--
break
}
@@ -696,7 +608,7 @@ LOOP:
case *nodes.LeafNode[V]:
// reached a path compressed prefix, stop traversing
- if kid.Prefix.Bits() > bits || !kid.Prefix.Contains(ip) {
+ if kid.Prefix.Bits() > pfxLen || !kid.Prefix.Contains(ip) {
break LOOP
}
return kid.Prefix, true
@@ -705,7 +617,7 @@ LOOP:
// the bits of the fringe are defined by the depth
// maybe the LPM isn't needed, saves some cycles
fringeBits := (depth + 1) << 3
- if fringeBits > bits {
+ if fringeBits > pfxLen {
break LOOP
}
@@ -723,7 +635,7 @@ LOOP:
// start backtracking, unwind the stack
for ; depth >= 0; depth-- {
- depth = depth & nodes.DepthMask // BCE
+ depth &= nodes.DepthMask // BCE
n = stack[depth]
@@ -732,15 +644,13 @@ LOOP:
continue
}
- // only the lastOctet may have a different prefix len
- // all others are just host routes
var idx uint8
octet = octets[depth]
- // Last “octet” from prefix, update/insert prefix into node.
- // Note: For /32 and /128, depth never reaches lastOctetPlusOne (4 or 16),
- // so those are handled below via the fringe/leaf path.
- if depth == lastOctetPlusOne {
- idx = art.PfxToIdx(octet, lastBits)
+
+ // only the final stride may have a different prefix len
+ // all others are just host routes
+ if depth == strideCount {
+ idx = art.PfxToIdx(octet, modBits)
} else {
idx = art.OctetToIdx(octet)
}
diff --git a/vendor/github.com/gaissmai/bart/litemethodsgenerated.go b/vendor/github.com/gaissmai/bart/litemethodsgenerated.go
index 98375180b5..e417f7be7f 100644
--- a/vendor/github.com/gaissmai/bart/litemethodsgenerated.go
+++ b/vendor/github.com/gaissmai/bart/litemethodsgenerated.go
@@ -1,6 +1,6 @@
// Code generated from file "commonmethods_tmpl.go"; DO NOT EDIT.
-// Copyright (c) 2025 Karl Gaissmaier
+// Copyright (c) 2026 Karl Gaissmaier
// SPDX-License-Identifier: MIT
package bart
@@ -266,9 +266,6 @@ func (t *liteTable[V]) ModifyPersist(pfx netip.Prefix, cb func(_ V, ok bool) (_
// Returns an empty iterator if the prefix is invalid.
func (t *liteTable[V]) Supernets(pfx netip.Prefix) iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
if !pfx.IsValid() {
return
}
@@ -298,9 +295,6 @@ func (t *liteTable[V]) Supernets(pfx netip.Prefix) iter.Seq2[netip.Prefix, V] {
// Returns an empty iterator if the prefix is invalid.
func (t *liteTable[V]) Subnets(pfx netip.Prefix) iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
if !pfx.IsValid() {
return
}
@@ -351,15 +345,12 @@ func (t *liteTable[V]) OverlapsPrefix(pfx netip.Prefix) bool {
// This is useful for conflict detection, policy enforcement,
// or validating mutually exclusive routing domains.
func (t *liteTable[V]) Overlaps(o *liteTable[V]) bool {
- if o == nil {
- return false
- }
return t.Overlaps4(o) || t.Overlaps6(o)
}
// Overlaps4 is like [liteTable.Overlaps] but for the v4 routing table only.
func (t *liteTable[V]) Overlaps4(o *liteTable[V]) bool {
- if o == nil || t.size4 == 0 || o.size4 == 0 {
+ if t.size4 == 0 || o.size4 == 0 {
return false
}
return t.root4.Overlaps(&o.root4, 0)
@@ -367,7 +358,7 @@ func (t *liteTable[V]) Overlaps4(o *liteTable[V]) bool {
// Overlaps6 is like [liteTable.Overlaps] but for the v6 routing table only.
func (t *liteTable[V]) Overlaps6(o *liteTable[V]) bool {
- if o == nil || t.size6 == 0 || o.size6 == 0 {
+ if t.size6 == 0 || o.size6 == 0 {
return false
}
return t.root6.Overlaps(&o.root6, 0)
@@ -380,7 +371,15 @@ func (t *liteTable[V]) Overlaps6(o *liteTable[V]) bool {
// This duplicate is shallow-copied by default, but if the value type V implements the
// Clone method, the value is deeply cloned before insertion. See also liteTable.Clone.
func (t *liteTable[V]) Union(o *liteTable[V]) {
- if o == nil || o == t || (o.size4 == 0 && o.size6 == 0) {
+ // panics on nil receiver
+ _ = t.size4
+
+ // panics on nil argument
+ if o.size4 == 0 && o.size6 == 0 {
+ return
+ }
+ // t is unchanged
+ if o == t {
return
}
@@ -398,10 +397,17 @@ func (t *liteTable[V]) Union(o *liteTable[V]) {
// UnionPersist is similar to [Union] but the receiver isn't modified.
//
// All nodes touched during union are cloned and a new *liteTable is returned.
-// If o is nil or empty, no nodes are touched and the receiver may be
+// If o is empty, no nodes are touched and the receiver may be
// returned unchanged.
func (t *liteTable[V]) UnionPersist(o *liteTable[V]) *liteTable[V] {
- if o == nil || o == t || (o.size4 == 0 && o.size6 == 0) {
+ // panics on nil receiver
+ _ = t.size4
+
+ // panics on nil argument
+ if o.size4 == 0 && o.size6 == 0 {
+ return t
+ }
+ if o == t {
return t
}
@@ -439,21 +445,16 @@ func (t *liteTable[V]) UnionPersist(o *liteTable[V]) *liteTable[V] {
// It ensures both trees (IPv4-based and IPv6-based) have the same sizes and
// recursively compares their root nodes.
//
-// Value comparisons use reflect.DeepEqual by default. To avoid the potentially
-// expensive reflect.DeepEqual, the payload type V can provide custom equality
-// by implementing the following method:
+// If V implements an `Equal(V) bool` method, its custom equality logic is used.
+// Otherwise, values are compared directly using the == operator.
//
-// Equal(other V) bool
+// Note: If V implements `Equal(V) bool` with a pointer receiver, the Equal
+// method should handle nil receivers gracefully.
//
-// Example:
-//
-// type MyValue struct { ID int }
-// func (v MyValue) Equal(other MyValue) bool { return v.ID == other.ID }
-//
-// The bart package will automatically detect and use this method via Go's
-// structural typing.
+// ATTENTION: If V is not comparable at runtime (such as a slice or map without an `Equal`
+// method), a runtime panic will occur.
func (t *liteTable[V]) Equal(o *liteTable[V]) bool {
- if o == nil || t.size4 != o.size4 || t.size6 != o.size6 {
+ if t.size4 != o.size4 || t.size6 != o.size6 {
return false
}
if o == t {
@@ -478,11 +479,10 @@ func (t *liteTable[V]) Equal(o *liteTable[V]) bool {
//
// The bart package will automatically detect and use this method via Go's
// structural typing.
+//
+// Note: If V implements Clone() V with a pointer receiver, the Clone
+// method should handle nil receivers gracefully.
func (t *liteTable[V]) Clone() *liteTable[V] {
- if t == nil {
- return nil
- }
-
c := new(liteTable[V])
cloneFn := value.CloneFnFactory[V]()
@@ -513,35 +513,14 @@ func (t *liteTable[V]) Size6() int {
// All returns an iterator over all prefix–value pairs in the table.
//
-// The entries from both IPv4 and IPv6 subtries are yielded using an internal recursive traversal.
-// The iteration order is unspecified and may vary between calls; for a stable order, use AllSorted.
-//
-// You can use All directly in a for-range loop without providing a yield function.
-// The Go compiler automatically synthesizes the yield callback for you:
-//
-// for prefix, value := range t.All() {
-// fmt.Println(prefix, value)
-// }
+// The iteration order is unspecified and may vary between calls; for a stable order,
+// use [liteTable.AllSorted].
//
-// Under the hood, the loop body is passed as a yield function to the iterator.
-// If you break or return from the loop, iteration stops early as expected.
-//
-// IMPORTANT: Modifying or deleting entries during iteration is not allowed,
+// IMPORTANT: Modifying the table during iteration is not allowed,
// as this would interfere with the internal traversal and may corrupt or
-// prematurely terminate the iteration. If mutation of the table during
-// traversal is required use persistent table methods, e.g.
-//
-// pt := t // shallow copy of t
-// for pfx, val := range t.All() {
-// if cond(pfx, val) {
-// pt = pt.DeletePersist(pfx)
-// }
-// }
+// prematurely terminate the iteration.
func (t *liteTable[V]) All() iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
_ = t.root4.AllRec(stridePath{}, 0, true, yield) && t.root6.AllRec(stridePath{}, 0, false, yield)
}
}
@@ -549,9 +528,6 @@ func (t *liteTable[V]) All() iter.Seq2[netip.Prefix, V] {
// All4 is like [liteTable.All] but only for the v4 routing table.
func (t *liteTable[V]) All4() iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
_ = t.root4.AllRec(stridePath{}, 0, true, yield)
}
}
@@ -559,35 +535,14 @@ func (t *liteTable[V]) All4() iter.Seq2[netip.Prefix, V] {
// All6 is like [liteTable.All] but only for the v6 routing table.
func (t *liteTable[V]) All6() iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
_ = t.root6.AllRec(stridePath{}, 0, false, yield)
}
}
-// AllSorted returns an iterator over all prefix–value pairs in the table,
-// ordered in canonical CIDR prefix sort order.
-//
-// This can be used directly with a for-range loop;
-// the Go compiler provides the yield function implicitly:
-//
-// for prefix, value := range t.AllSorted() {
-// fmt.Println(prefix, value)
-// }
-//
-// The traversal is stable and predictable across calls.
-// Iteration stops early if you break out of the loop.
-//
-// IMPORTANT: Deleting entries during iteration is not allowed,
-// as this would interfere with the internal traversal and may corrupt or
-// prematurely terminate the iteration. If mutation of the table during
-// traversal is required use persistent table methods.
+// AllSorted is like [liteTable.All] but the iteration is ordered in canonical
+// CIDR prefix sort order.
func (t *liteTable[V]) AllSorted() iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
_ = t.root4.AllRecSorted(stridePath{}, 0, true, yield) &&
t.root6.AllRecSorted(stridePath{}, 0, false, yield)
}
@@ -596,9 +551,6 @@ func (t *liteTable[V]) AllSorted() iter.Seq2[netip.Prefix, V] {
// AllSorted4 is like [liteTable.AllSorted] but only for the v4 routing table.
func (t *liteTable[V]) AllSorted4() iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
_ = t.root4.AllRecSorted(stridePath{}, 0, true, yield)
}
}
@@ -606,9 +558,6 @@ func (t *liteTable[V]) AllSorted4() iter.Seq2[netip.Prefix, V] {
// AllSorted6 is like [liteTable.AllSorted] but only for the v6 routing table.
func (t *liteTable[V]) AllSorted6() iter.Seq2[netip.Prefix, V] {
return func(yield func(netip.Prefix, V) bool) {
- if t == nil {
- return
- }
_ = t.root6.AllRecSorted(stridePath{}, 0, false, yield)
}
}
@@ -636,12 +585,9 @@ func (t *liteTable[V]) AllSorted6() iter.Seq2[netip.Prefix, V] {
// │ └─ 2001:db8::/32 (V)
// └─ fe80::/10 (V)
func (t *liteTable[V]) Fprint(w io.Writer) error {
- if w == nil {
+ if w == nil && t != nil {
return fmt.Errorf("nil writer")
}
- if t == nil {
- return nil
- }
// v4
if err := t.fprint(w, true); err != nil {
@@ -691,10 +637,6 @@ func (t *liteTable[V]) MarshalText() ([]byte, error) {
// MarshalJSON dumps the table into two sorted lists: for ipv4 and ipv6.
// Every root and subnet is an array, not a map, because the order matters.
func (t *liteTable[V]) MarshalJSON() ([]byte, error) {
- if t == nil {
- return []byte("null"), nil
- }
-
result := struct {
Ipv4 []DumpListNode[V] `json:"ipv4,omitempty"`
Ipv6 []DumpListNode[V] `json:"ipv6,omitempty"`
@@ -714,18 +656,12 @@ func (t *liteTable[V]) MarshalJSON() ([]byte, error) {
// DumpList4 dumps the ipv4 tree into a list of roots and their subnets.
// It can be used to analyze the tree or build the text or JSON serialization.
func (t *liteTable[V]) DumpList4() []DumpListNode[V] {
- if t == nil {
- return nil
- }
return t.dumpListRec(&t.root4, 0, stridePath{}, 0, true)
}
// DumpList6 dumps the ipv6 tree into a list of roots and their subnets.
// It can be used to analyze the tree or build custom JSON representation.
func (t *liteTable[V]) DumpList6() []DumpListNode[V] {
- if t == nil {
- return nil
- }
return t.dumpListRec(&t.root6, 0, stridePath{}, 0, false)
}
@@ -775,10 +711,6 @@ func (t *liteTable[V]) dumpString() string {
// dump the table structure and all the nodes to w.
func (t *liteTable[V]) dump(w io.Writer) {
- if t == nil {
- return
- }
-
if t.size4 > 0 {
stats := t.root4.StatsRec()
fmt.Fprintln(w)
diff --git a/vendor/github.com/gokrazy/updater/updater.go b/vendor/github.com/gokrazy/updater/updater.go
index 9be0d04d47..2221c39363 100644
--- a/vendor/github.com/gokrazy/updater/updater.go
+++ b/vendor/github.com/gokrazy/updater/updater.go
@@ -16,7 +16,6 @@ import (
"log"
"net/http"
"net/url"
- "slices"
"strings"
)
@@ -76,7 +75,12 @@ const (
// Supports returns whether the target is known to support the specified update
// protocol feature.
func (t *Target) Supports(feature ProtocolFeature) bool {
- return slices.Contains(t.supports, string(feature))
+ for _, f := range t.supports {
+ if f == string(feature) {
+ return true
+ }
+ }
+ return false
}
// StreamTo streams from the specified io.Reader to the specified destination:
@@ -118,7 +122,7 @@ func (t *Target) StreamTo(ctx context.Context, dest string, r io.Reader) error {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("unexpected HTTP status code: got %v, want %v (body %q)", resp.Status, want, string(body))
}
- remoteHash, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ remoteHash, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
@@ -162,7 +166,7 @@ func (t *Target) Put(ctx context.Context, dest string, r io.Reader) error {
// Switch changes the active root partition from the currently running root
// partition to the currently inactive root partition.
func (t *Target) Switch(ctx context.Context) error {
- req, err := http.NewRequestWithContext(ctx, "POST", t.baseURL+"update/switch", http.NoBody)
+ req, err := http.NewRequestWithContext(ctx, "POST", t.baseURL+"update/switch", nil)
if err != nil {
return err
}
@@ -181,7 +185,7 @@ func (t *Target) Switch(ctx context.Context) error {
// Testboot marks the inactive root partition to be tested upon the next boot,
// and made active if the test boot succeeds.
func (t *Target) Testboot(ctx context.Context) error {
- req, err := http.NewRequestWithContext(ctx, "POST", t.baseURL+"update/testboot", http.NoBody)
+ req, err := http.NewRequestWithContext(ctx, "POST", t.baseURL+"update/testboot", nil)
if err != nil {
return err
}
@@ -245,7 +249,7 @@ func (t *Target) Reboot(ctx context.Context, opts ...RebootOption) error {
url += "?" + strings.Join(params, "&")
}
- req, err := http.NewRequestWithContext(ctx, "POST", url, http.NoBody)
+ req, err := http.NewRequestWithContext(ctx, "POST", url, nil)
if err != nil {
return err
}
@@ -335,7 +339,7 @@ func (t *Target) InstalledEEPROM() EEPROMVersion {
}
func (t *Target) requestFeatures(ctx context.Context) error {
- req, err := http.NewRequestWithContext(ctx, "GET", t.baseURL+"update/features", http.NoBody)
+ req, err := http.NewRequestWithContext(ctx, "GET", t.baseURL+"update/features", nil)
if err != nil {
return err
}
@@ -357,7 +361,7 @@ func (t *Target) requestFeatures(ctx context.Context) error {
return fmt.Errorf("unexpected HTTP status code: got %d, want %d (body %q)", got, want, string(body))
}
- body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
+ body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
@@ -399,7 +403,7 @@ type EEPROMVersion struct {
}
func (t *Target) getEEPROMFromStatus(ctx context.Context) (*EEPROMVersion, error) {
- req, err := http.NewRequestWithContext(ctx, "GET", t.baseURL, http.NoBody)
+ req, err := http.NewRequestWithContext(ctx, "GET", t.baseURL, nil)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md b/vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md
index a10d3fc8dc..3879f14aa9 100644
--- a/vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md
+++ b/vendor/github.com/lucasb-eyer/go-colorful/CHANGELOG.md
@@ -8,6 +8,12 @@ but only releases after v1.0.3 properly adhere to it.
## [Unreleased]
+## [1.4.0] - 2026-03-28
+### Added
+- Constructors, decomposers, and blend functions for the CSS Color Level 4 wide-gamut RGB color spaces `DisplayP3`, `A98Rgb`, `ProPhotoRgb`, and `Rec2020` (#81)
+- `XyzD50`, `Color.XyzD50`, `D50ToD65`, and `D65ToD50` for working with D50-based color spaces (#81)
+- `HexColor` now implements `fmt.Stringer`
+
## [1.3.0] - 2025-09-08
### Added
- `BlendLinearRgb` (#50)
@@ -19,7 +25,7 @@ but only releases after v1.0.3 properly adhere to it.
- Functions BlendOkLab and BlendOkLch (#70)
## Changed
-- `Hex()` parsing is much faster (#78)
+- `Hex()` parsing is much faster (#78). However, it doesn't tolerate hex codes with alpha anymore (previously ignoring the alpha was unintentional).
### Fixed
- Fix bug when doing HSV/HCL blending between a gray color and non-gray color (#60)
diff --git a/vendor/github.com/lucasb-eyer/go-colorful/README.md b/vendor/github.com/lucasb-eyer/go-colorful/README.md
index b3bb545cf6..1da19f703b 100644
--- a/vendor/github.com/lucasb-eyer/go-colorful/README.md
+++ b/vendor/github.com/lucasb-eyer/go-colorful/README.md
@@ -34,6 +34,8 @@ Go-Colorful stores colors in RGB and provides methods from converting these to v
- **CIE LCh(uv):** Called `LuvLCh` in code, this is a cylindrical transformation of the CIE-L\*u\*v\* color space. Like HCL above: H° is in [0..360], C\* almost in [0..1] and L\* as in CIE-L\*u\*v\*.
- **HSLuv:** The better alternative to HSL, see [here](https://www.hsluv.org/) and [here](https://www.kuon.ch/post/2020-03-08-hsluv/). Hue in [0..360], Saturation and Luminance in [0..1].
- **HPLuv:** A variant of HSLuv. The color space is smoother, but only pastel colors can be included. Because the valid colors are limited, it's easy to get invalid Saturation values way above 1.0, indicating the color can't be represented in HPLuv because it's not pastel.
+- **Oklab:** A perceptual color space by Björn Ottosson that improves on CIE-L\*a\*b\* with better perceptual uniformity, especially for blue hues. L in [0..1], a and b roughly in [-0.5..0.5]. See [Oklab](https://bottosson.github.io/posts/oklab/).
+- **Oklch:** The cylindrical (polar) representation of Oklab, similar to HCL. L in [0..1], C roughly in [0..0.5], h° in [0..360].
For the colorspaces where it makes sense (XYZ, Lab, Luv, HCl), the
[D65](http://en.wikipedia.org/wiki/Illuminant_D65) is used as reference white
@@ -96,6 +98,8 @@ c = colorful.Xyy(0.219895, 0.221839, 0.190837)
c = colorful.Lab(0.507850, 0.040585,-0.370945)
c = colorful.Luv(0.507849,-0.194172,-0.567924)
c = colorful.Hcl(276.2440, 0.373160, 0.507849)
+c = colorful.OkLab(0.577227, -0.021391, -0.104541)
+c = colorful.OkLch(0.577227, 0.106707, 258.435657)
fmt.Printf("RGB values: %v, %v, %v", c.R, c.G, c.B)
```
@@ -109,6 +113,8 @@ x, y, Y := c.Xyy()
l, a, b := c.Lab()
l, u, v := c.Luv()
h, c, l := c.Hcl()
+l, a, b = c.OkLab()
+l, c, h = c.OkLch()
```
Note that, because of Go's unfortunate choice of requiring an initial uppercase,
@@ -190,7 +196,7 @@ it only if you really know what you're doing. It will eat your cat.
Blending is highly connected to distance, since it basically "walks through" the
colorspace thus, if the colorspace maps distances well, the walk is "smooth".
-Colorful comes with blending functions in RGB, HSV and any of the LAB spaces.
+Colorful comes with blending functions in RGB, HSV, Oklab, Oklch, and any of the CIE-LAB spaces.
Of course, you'd rather want to use the blending functions of the LAB spaces since
these spaces map distances well but, just in case, here is an example showing
you how the blendings (`#fdffcc` to `#242a42`) are done in the various spaces:
@@ -472,11 +478,12 @@ section above.
Who?
====
-This library was developed by Lucas Beyer with contributions from
-Bastien Dejean (@baskerville), Phil Kulak (@pkulak), Christian Muehlhaeuser (@muesli), and Scott Pakin (@spakin).
-
-It is now maintained by makeworld (@makew0rld).
+This library was originally developed by Lucas Beyer, with notable
+contributions from Bastien Dejean (@baskerville), Phil Kulak (@pkulak),
+Christian Muehlhaeuser (@muesli), Scott Pakin (@spakin), and many others.
+See the [contributors list](https://github.com/lucasb-eyer/go-colorful/graphs/contributors) for the full roster.
+It is currently maintained by makeworld (@makew0rld).
## License
diff --git a/vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go b/vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go
index ad8b06cc94..26f3573043 100644
--- a/vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go
+++ b/vendor/github.com/lucasb-eyer/go-colorful/hexcolor.go
@@ -34,6 +34,10 @@ func (hc *HexColor) Value() (driver.Value, error) {
return Color(*hc).Hex(), nil
}
+func (hc HexColor) String() string {
+ return Color(hc).Hex()
+}
+
func (e errUnsupportedType) Error() string {
return fmt.Sprintf("unsupported type: got %v, want a %s", e.got, e.want)
}
diff --git a/vendor/github.com/lucasb-eyer/go-colorful/widegamut.go b/vendor/github.com/lucasb-eyer/go-colorful/widegamut.go
new file mode 100644
index 0000000000..6805a2b96f
--- /dev/null
+++ b/vendor/github.com/lucasb-eyer/go-colorful/widegamut.go
@@ -0,0 +1,290 @@
+package colorful
+
+import "math"
+
+// Wide-gamut RGB color spaces from CSS Color Level 4.
+// https://www.w3.org/TR/css-color-4/#color-conversion-code
+
+/// Bradford ///
+////////////////
+// Bradford chromatic adaptation between D50 and D65 illuminants.
+
+func D50ToD65(x, y, z float64) (xo, yo, zo float64) {
+ xo = 0.9555766*x - 0.0230393*y + 0.0631636*z
+ yo = -0.0282895*x + 1.0099416*y + 0.0210077*z
+ zo = 0.0122982*x - 0.0204830*y + 1.3299098*z
+ return
+}
+
+func D65ToD50(x, y, z float64) (xo, yo, zo float64) {
+ xo = 1.0479298208405488*x + 0.022946793341019088*y - 0.05019222954313557*z
+ yo = 0.029627815688159344*x + 0.990434484573249*y - 0.01707382502938514*z
+ zo = -0.009243058152591178*x + 0.015055144896577895*y + 0.7518742899580008*z
+ return
+}
+
+/// XYZ D50 ///
+///////////////
+
+func XyzD50(x, y, z float64) Color {
+ return Xyz(D50ToD65(x, y, z))
+}
+
+func (col Color) XyzD50() (x, y, z float64) {
+ return D65ToD50(col.Xyz())
+}
+
+/// Display P3 ///
+//////////////////
+// Uses the sRGB transfer function with DCI-P3 primaries.
+
+func DisplayP3ToLinearRgb(r, g, b float64) (rl, gl, bl float64) {
+ rl = linearize(r)
+ gl = linearize(g)
+ bl = linearize(b)
+ return
+}
+
+func LinearDisplayP3ToXyz(r, g, b float64) (x, y, z float64) {
+ x = 0.4865709486482162*r + 0.26566769316909306*g + 0.1982172852343625*b
+ y = 0.2289745640697488*r + 0.6917385218365064*g + 0.079286914093745*b
+ z = 0.04511338185890264*g + 1.043944368900976*b
+ return
+}
+
+func XyzToLinearDisplayP3(x, y, z float64) (r, g, b float64) {
+ r = 2.493496911941425*x - 0.9313836179191239*y - 0.40271078445071684*z
+ g = -0.8294889695615747*x + 1.7626640603183463*y + 0.023624685841943577*z
+ b = 0.035845830243784335*x - 0.07617238926804182*y + 0.9568845240076872*z
+ return
+}
+
+func DisplayP3(r, g, b float64) Color {
+ rl, gl, bl := DisplayP3ToLinearRgb(r, g, b)
+ x, y, z := LinearDisplayP3ToXyz(rl, gl, bl)
+ return Xyz(x, y, z)
+}
+
+func (col Color) DisplayP3() (r, g, b float64) {
+ x, y, z := col.Xyz()
+ rl, gl, bl := XyzToLinearDisplayP3(x, y, z)
+ r = delinearize(rl)
+ g = delinearize(gl)
+ b = delinearize(bl)
+ return
+}
+
+// BlendDisplayP3 blends two colors in the Display P3 color-space.
+// t == 0 results in c1, t == 1 results in c2
+func (c1 Color) BlendDisplayP3(c2 Color, t float64) Color {
+ r1, g1, b1 := c1.DisplayP3()
+ r2, g2, b2 := c2.DisplayP3()
+ return DisplayP3(
+ r1+t*(r2-r1),
+ g1+t*(g2-g1),
+ b1+t*(b2-b1))
+}
+
+/// A98 RGB ///
+///////////////
+// Adobe RGB (1998) color space.
+
+func linearizeA98(v float64) float64 {
+ sign := 1.0
+ if v < 0 {
+ sign = -1.0
+ v = -v
+ }
+ return sign * math.Pow(v, 563.0/256.0)
+}
+
+func delinearizeA98(v float64) float64 {
+ sign := 1.0
+ if v < 0 {
+ sign = -1.0
+ v = -v
+ }
+ return sign * math.Pow(v, 256.0/563.0)
+}
+
+func A98RgbToLinearRgb(r, g, b float64) (rl, gl, bl float64) {
+ rl = linearizeA98(r)
+ gl = linearizeA98(g)
+ bl = linearizeA98(b)
+ return
+}
+
+func LinearA98RgbToXyz(r, g, b float64) (x, y, z float64) {
+ x = 0.5766690429101305*r + 0.1855582379065463*g + 0.1882286462349947*b
+ y = 0.29734497525053605*r + 0.6273635662554661*g + 0.07529145849399788*b
+ z = 0.02703136138641234*r + 0.07068885253582723*g + 0.9913375368376388*b
+ return
+}
+
+func XyzToLinearA98Rgb(x, y, z float64) (r, g, b float64) {
+ r = 2.0415879038107327*x - 0.5650069742788597*y - 0.34473135077832956*z
+ g = -0.9692436362808795*x + 1.8759675015077202*y + 0.04155505740717559*z
+ b = 0.013444280632031142*x - 0.11836239223101838*y + 1.0151749943912054*z
+ return
+}
+
+func A98Rgb(r, g, b float64) Color {
+ rl, gl, bl := A98RgbToLinearRgb(r, g, b)
+ x, y, z := LinearA98RgbToXyz(rl, gl, bl)
+ return Xyz(x, y, z)
+}
+
+func (col Color) A98Rgb() (r, g, b float64) {
+ x, y, z := col.Xyz()
+ rl, gl, bl := XyzToLinearA98Rgb(x, y, z)
+ r = delinearizeA98(rl)
+ g = delinearizeA98(gl)
+ b = delinearizeA98(bl)
+ return
+}
+
+// BlendA98Rgb blends two colors in the A98 RGB color-space.
+// t == 0 results in c1, t == 1 results in c2
+func (c1 Color) BlendA98Rgb(c2 Color, t float64) Color {
+ r1, g1, b1 := c1.A98Rgb()
+ r2, g2, b2 := c2.A98Rgb()
+ return A98Rgb(
+ r1+t*(r2-r1),
+ g1+t*(g2-g1),
+ b1+t*(b2-b1))
+}
+
+/// ProPhoto RGB ///
+////////////////////
+// ProPhoto RGB (ROMM RGB) uses D50 illuminant.
+
+func linearizeProPhoto(v float64) float64 {
+ if v <= 16.0/512.0 {
+ return v / 16.0
+ }
+ return math.Pow(v, 1.8)
+}
+
+func delinearizeProPhoto(v float64) float64 {
+ if v < 1.0/512.0 {
+ return 16.0 * v
+ }
+ return math.Pow(v, 1.0/1.8)
+}
+
+func ProPhotoRgbToLinearRgb(r, g, b float64) (rl, gl, bl float64) {
+ rl = linearizeProPhoto(r)
+ gl = linearizeProPhoto(g)
+ bl = linearizeProPhoto(b)
+ return
+}
+
+func LinearProPhotoRgbToXyzD50(r, g, b float64) (x, y, z float64) {
+ x = 0.7977604896723027*r + 0.13518583717574031*g + 0.0313493495815248*b
+ y = 0.2880711282292934*r + 0.7118432178101014*g + 0.00008565396060525902*b
+ z = 0.8251046025104602 * b
+ return
+}
+
+func XyzD50ToLinearProPhotoRgb(x, y, z float64) (r, g, b float64) {
+ r = 1.3457989731028281*x - 0.25558010007997534*y - 0.05110628506753401*z
+ g = -0.5446224939028347*x + 1.5082327413132781*y + 0.02053603239147973*z
+ b = 1.2119675456389454 * z
+ return
+}
+
+func ProPhotoRgb(r, g, b float64) Color {
+ rl, gl, bl := ProPhotoRgbToLinearRgb(r, g, b)
+ x, y, z := LinearProPhotoRgbToXyzD50(rl, gl, bl)
+ return XyzD50(x, y, z)
+}
+
+func (col Color) ProPhotoRgb() (r, g, b float64) {
+ x, y, z := col.XyzD50()
+ rl, gl, bl := XyzD50ToLinearProPhotoRgb(x, y, z)
+ r = delinearizeProPhoto(rl)
+ g = delinearizeProPhoto(gl)
+ b = delinearizeProPhoto(bl)
+ return
+}
+
+// BlendProPhotoRgb blends two colors in the ProPhoto RGB color-space.
+// t == 0 results in c1, t == 1 results in c2
+func (c1 Color) BlendProPhotoRgb(c2 Color, t float64) Color {
+ r1, g1, b1 := c1.ProPhotoRgb()
+ r2, g2, b2 := c2.ProPhotoRgb()
+ return ProPhotoRgb(
+ r1+t*(r2-r1),
+ g1+t*(g2-g1),
+ b1+t*(b2-b1))
+}
+
+/// Rec. 2020 ///
+/////////////////
+// ITU-R BT.2020 color space.
+
+const (
+ rec2020Alpha = 1.09929682680944
+ rec2020Beta = 0.018053968510807
+)
+
+func linearizeRec2020(v float64) float64 {
+ if v < rec2020Beta*4.5 {
+ return v / 4.5
+ }
+ return math.Pow((v+rec2020Alpha-1)/rec2020Alpha, 1.0/0.45)
+}
+
+func delinearizeRec2020(v float64) float64 {
+ if v < rec2020Beta {
+ return 4.5 * v
+ }
+ return rec2020Alpha*math.Pow(v, 0.45) - (rec2020Alpha - 1)
+}
+
+func Rec2020ToLinearRgb(r, g, b float64) (rl, gl, bl float64) {
+ rl = linearizeRec2020(r)
+ gl = linearizeRec2020(g)
+ bl = linearizeRec2020(b)
+ return
+}
+
+func LinearRec2020ToXyz(r, g, b float64) (x, y, z float64) {
+ x = 0.6369580483012914*r + 0.14461690358620832*g + 0.1688809751641721*b
+ y = 0.2627002120112671*r + 0.6779980715188708*g + 0.05930171646986196*b
+ z = 0.028072693049087428*g + 1.0609850577107909*b
+ return
+}
+
+func XyzToLinearRec2020(x, y, z float64) (r, g, b float64) {
+ r = 1.7166511879712674*x - 0.35567078377639233*y - 0.25336628137365974*z
+ g = -0.666684351832489*x + 1.616481236634939*y + 0.0157685458139402*z
+ b = 0.017639857445310783*x - 0.042770613257808524*y + 0.9421031212354738*z
+ return
+}
+
+func Rec2020(r, g, b float64) Color {
+ rl, gl, bl := Rec2020ToLinearRgb(r, g, b)
+ x, y, z := LinearRec2020ToXyz(rl, gl, bl)
+ return Xyz(x, y, z)
+}
+
+func (col Color) Rec2020() (r, g, b float64) {
+ x, y, z := col.Xyz()
+ rl, gl, bl := XyzToLinearRec2020(x, y, z)
+ r = delinearizeRec2020(rl)
+ g = delinearizeRec2020(gl)
+ b = delinearizeRec2020(bl)
+ return
+}
+
+// BlendRec2020 blends two colors in the Rec. 2020 color-space.
+// t == 0 results in c1, t == 1 results in c2
+func (c1 Color) BlendRec2020(c2 Color, t float64) Color {
+ r1, g1, b1 := c1.Rec2020()
+ r2, g2, b2 := c2.Rec2020()
+ return Rec2020(
+ r1+t*(r2-r1),
+ g1+t*(g2-g1),
+ b1+t*(b2-b1))
+}
diff --git a/vendor/github.com/mattn/go-runewidth/SECURITY.md b/vendor/github.com/mattn/go-runewidth/SECURITY.md
new file mode 100644
index 0000000000..a6898ee701
--- /dev/null
+++ b/vendor/github.com/mattn/go-runewidth/SECURITY.md
@@ -0,0 +1,25 @@
+# Security Policy
+
+## Supported Versions
+
+The following versions of go-runewidth are currently supported with
+security updates.
+
+| Version | Supported |
+| -------- | ------------------ |
+| 0.0.23 | :white_check_mark: |
+| < 0.0.23 | :x: |
+
+## Reporting a Vulnerability
+
+If you discover a security vulnerability in go-runewidth, please report it
+privately via GitHub's "Report a vulnerability" feature on the Security tab
+of the repository (https://github.com/mattn/go-runewidth/security), or by
+emailing the maintainer at mattn.jp@gmail.com.
+
+Please include a description of the issue, reproduction steps, and the
+affected version. You can expect an initial response within one week. If
+the vulnerability is accepted, a fix will be prepared and a new release
+will be published; you will be credited in the release notes unless you
+request otherwise. If the report is declined, you will receive an
+explanation of the reasoning.
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go
index a8c9c1fb10..6b958fdd49 100644
--- a/vendor/github.com/mattn/go-runewidth/runewidth.go
+++ b/vendor/github.com/mattn/go-runewidth/runewidth.go
@@ -2,7 +2,9 @@ package runewidth
import (
"os"
+ "sort"
"strings"
+ "unicode/utf8"
"github.com/clipperhouse/uax29/v2/graphemes"
)
@@ -23,10 +25,54 @@ var (
}
)
+var (
+ zerowidth table // combining + nonprint merged for faster zero-width lookup
+ widewidth table // ambiguous + doublewidth merged for EA path
+ eastAsianWidth widthTable
+ eastAsianWidth0 [0x300]byte
+)
+
func init() {
+ zerowidth = mergeIntervals(combining, nonprint)
+ widewidth = mergeIntervals(ambiguous, doublewidth)
+ eastAsianWidth = makeWidthTable(zerowidth, widewidth)
+ for r := range eastAsianWidth0 {
+ eastAsianWidth0[r] = byte(runeWidthEastAsian(rune(r)))
+ }
handleEnv()
}
+func mergeIntervals(t1, t2 table) table {
+ merged := make(table, 0, len(t1)+len(t2))
+ i, j := 0, 0
+ for i < len(t1) && j < len(t2) {
+ if t1[i].first <= t2[j].first {
+ merged = append(merged, t1[i])
+ i++
+ } else {
+ merged = append(merged, t2[j])
+ j++
+ }
+ }
+ merged = append(merged, t1[i:]...)
+ merged = append(merged, t2[j:]...)
+ if len(merged) == 0 {
+ return merged
+ }
+ result := merged[:1]
+ for _, iv := range merged[1:] {
+ last := &result[len(result)-1]
+ if iv.first <= last.last+1 {
+ if iv.last > last.last {
+ last.last = iv.last
+ }
+ } else {
+ result = append(result, iv)
+ }
+ }
+ return result
+}
+
func handleEnv() {
env := os.Getenv("RUNEWIDTH_EASTASIAN")
if env == "" {
@@ -51,15 +97,14 @@ type interval struct {
type table []interval
-func inTables(r rune, ts ...table) bool {
- for _, t := range ts {
- if inTable(r, t) {
- return true
- }
- }
- return false
+type widthInterval struct {
+ first rune
+ last rune
+ width byte
}
+type widthTable []widthInterval
+
func inTable(r rune, t table) bool {
if r < t[0].first {
return false
@@ -86,6 +131,71 @@ func inTable(r rune, t table) bool {
return false
}
+func makeWidthTable(zero, two table) widthTable {
+ wt := make(widthTable, 0, len(zero)+len(two))
+ zi := 0
+ for _, iv := range two {
+ start := iv.first
+ for zi < len(zero) && zero[zi].last < start {
+ zi++
+ }
+ for i := zi; i < len(zero) && zero[i].first <= iv.last; i++ {
+ if start < zero[i].first {
+ wt = append(wt, widthInterval{start, zero[i].first - 1, 2})
+ }
+ if start <= zero[i].last {
+ start = zero[i].last + 1
+ }
+ if start > iv.last {
+ break
+ }
+ }
+ if start <= iv.last {
+ wt = append(wt, widthInterval{start, iv.last, 2})
+ }
+ }
+ for _, iv := range zero {
+ wt = append(wt, widthInterval{iv.first, iv.last, 0})
+ }
+ sort.Slice(wt, func(i, j int) bool {
+ return wt[i].first < wt[j].first
+ })
+ return wt
+}
+
+func inWidthTable(r rune, t widthTable) (int, bool) {
+ if r < t[0].first {
+ return 0, false
+ }
+ if r > t[len(t)-1].last {
+ return 0, false
+ }
+
+ bot := 0
+ top := len(t) - 1
+ for top >= bot {
+ mid := (bot + top) >> 1
+
+ switch {
+ case t[mid].last < r:
+ bot = mid + 1
+ case t[mid].first > r:
+ top = mid - 1
+ default:
+ return int(t[mid].width), true
+ }
+ }
+
+ return 0, false
+}
+
+func runeWidthEastAsian(r rune) int {
+ if w, ok := inWidthTable(r, eastAsianWidth); ok {
+ return w
+ }
+ return 1
+}
+
var private = table{
{0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
}
@@ -123,36 +233,35 @@ func (c *Condition) RuneWidth(r rune) int {
}
// optimized version, verified by TestRuneWidthChecksums()
if !c.EastAsianWidth {
- switch {
- case r < 0x20:
- return 0
- case (r >= 0x7F && r <= 0x9F) || r == 0xAD: // nonprint
+ if r < 0x20 {
return 0
- case r < 0x300:
- return 1
- case inTable(r, narrow):
- return 1
- case inTables(r, nonprint, combining):
+ }
+ if (r >= 0x7F && r <= 0x9F) || r == 0xAD { // nonprint
return 0
- case inTable(r, doublewidth):
- return 2
- default:
+ }
+ if r < 0x300 {
return 1
}
- } else {
switch {
- case inTables(r, nonprint, combining):
+ case inTable(r, zerowidth):
return 0
- case inTable(r, narrow):
- return 1
- case inTables(r, ambiguous, doublewidth):
- return 2
- case !c.StrictEmojiNeutral && inTables(r, ambiguous, emoji, narrow):
+ case inTable(r, doublewidth):
return 2
default:
return 1
}
}
+
+ if r < 0x300 {
+ return int(eastAsianWidth0[r])
+ }
+ if w, ok := inWidthTable(r, eastAsianWidth); ok {
+ return w
+ }
+ if !c.StrictEmojiNeutral && inTable(r, emoji) {
+ return 2
+ }
+ return 1
}
// CreateLUT will create an in-memory lookup table of 557056 bytes for faster operation.
@@ -178,6 +287,33 @@ func (c *Condition) CreateLUT() {
// StringWidth return width as you can see
func (c *Condition) StringWidth(s string) (width int) {
+ if len(s) == 1 {
+ b := s[0]
+ if b < 0x20 || b == 0x7F {
+ return 0
+ }
+ return 1
+ }
+ if len(s) > 0 && len(s) <= utf8.UTFMax {
+ r, size := utf8.DecodeRuneInString(s)
+ if size == len(s) {
+ return c.RuneWidth(r)
+ }
+ }
+ // ASCII fast path: no grapheme clustering needed for pure ASCII
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if b >= 0x80 {
+ goto graphemes
+ }
+ if b >= 0x20 && b != 0x7F {
+ width++
+ }
+ }
+ return
+
+graphemes:
+ width = 0
g := graphemes.FromString(s)
for g.Next() {
var chWidth int
@@ -257,24 +393,25 @@ func (c *Condition) TruncateLeft(s string, w int, prefix string) string {
// Wrap return string wrapped with w cells
func (c *Condition) Wrap(s string, w int) string {
width := 0
- out := ""
+ var out strings.Builder
+ out.Grow(len(s) + len(s)/w + 1)
for _, r := range s {
cw := c.RuneWidth(r)
if r == '\n' {
- out += string(r)
+ out.WriteRune(r)
width = 0
continue
} else if width+cw > w {
- out += "\n"
+ out.WriteByte('\n')
width = 0
- out += string(r)
+ out.WriteRune(r)
width += cw
continue
}
- out += string(r)
+ out.WriteRune(r)
width += cw
}
- return out
+ return out.String()
}
// FillLeft return string filled in left by spaces in w cells
@@ -313,7 +450,7 @@ func RuneWidth(r rune) int {
// IsAmbiguousWidth returns whether is ambiguous width or not.
func IsAmbiguousWidth(r rune) bool {
- return inTables(r, private, ambiguous)
+ return inTable(r, private) || inTable(r, ambiguous)
}
// IsCombiningWidth returns whether is combining width or not.
diff --git a/vendor/github.com/mdlayher/genetlink/.golangci.yml b/vendor/github.com/mdlayher/genetlink/.golangci.yml
new file mode 100644
index 0000000000..1f10166aab
--- /dev/null
+++ b/vendor/github.com/mdlayher/genetlink/.golangci.yml
@@ -0,0 +1,16 @@
+version: "2"
+linters:
+ enable:
+ - misspell
+ - modernize
+ - revive
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+formatters:
+ exclusions:
+ generated: lax
diff --git a/vendor/github.com/mdlayher/genetlink/family_linux.go b/vendor/github.com/mdlayher/genetlink/family_linux.go
index 8c496f5b72..98273d6205 100644
--- a/vendor/github.com/mdlayher/genetlink/family_linux.go
+++ b/vendor/github.com/mdlayher/genetlink/family_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package genetlink
diff --git a/vendor/github.com/mdlayher/netlink/CHANGELOG.md b/vendor/github.com/mdlayher/netlink/CHANGELOG.md
index eac8e924c1..64589d14f0 100644
--- a/vendor/github.com/mdlayher/netlink/CHANGELOG.md
+++ b/vendor/github.com/mdlayher/netlink/CHANGELOG.md
@@ -1,5 +1,25 @@
# CHANGELOG
+## 1.9.0
+
+**This is the first release of package netlink that only supports Go 1.24+.**
+
+- [Improvement]: updated dependencies and Go version to 1.24; tests now run on
+ Go 1.24-1.26.
+- [New API]: [#236](https://github.com/mdlayher/netlink/pull/236) introduced
+ `Sequence` field to `OpError` for better error correlation.
+- [New API]: [#237](https://github.com/mdlayher/netlink/pull/237) added
+ `netlink.Conn.PID` method to retrieve the connection's PID, also known as port
+ ID.
+- [Improvement]: [#228](https://github.com/mdlayher/netlink/pull/228) fixed
+ skipping of specific tests on big-endian hosts.
+
+## 1.8.0
+
+- [Improvement]: Updated dependencies, test with Go 1.23 to 1.25.
+- [Improvement]: Use Go 1.21's binary.NativeEndian (#220)
+- [Improvement]: Expose socket ReadBuffer & WriteBuffer functions (#223)
+
## v1.7.2
- [Improvement]: updated dependencies, test with Go 1.20.
@@ -29,7 +49,7 @@ Users on older versions of Go must use v1.6.2.**
## v1.6.1
-- [Deprecation] [commit](https://github.com/mdlayher/netlink/commit/d1b69ea8697d721415c259ef8513ab699c6d3e96):
+- [Deprecation] [commit](https://github.com/mdlayher/netlink/commit/d1b69ea8697d721415c259ef8513ab699c6d3e96):
the `netlink.Socket` interface has been marked as deprecated. The abstraction
is awkward to use properly and disables much of the functionality of the Conn
type when the basic interface is implemented. Do not use.
diff --git a/vendor/github.com/mdlayher/netlink/LICENSE.md b/vendor/github.com/mdlayher/netlink/LICENSE.md
index 12f7105853..1eea1a5346 100644
--- a/vendor/github.com/mdlayher/netlink/LICENSE.md
+++ b/vendor/github.com/mdlayher/netlink/LICENSE.md
@@ -1,6 +1,6 @@
# MIT License
-Copyright (C) 2016-2022 Matt Layher
+Copyright (C) 2016-2026 Matt Layher
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
diff --git a/vendor/github.com/mdlayher/netlink/conn.go b/vendor/github.com/mdlayher/netlink/conn.go
index 7138665bce..a88efee92e 100644
--- a/vendor/github.com/mdlayher/netlink/conn.go
+++ b/vendor/github.com/mdlayher/netlink/conn.go
@@ -434,17 +434,20 @@ func (c *Conn) SetOption(option ConnOption, enable bool) error {
return newOpError("set-option", conn.SetOption(option, enable))
}
-// A bufferSetter is a Socket that supports setting connection buffer sizes.
-type bufferSetter interface {
+// A bufferedSocket is a Socket that supports getting & setting connection
+// buffer sizes.
+type bufferedSocket interface {
Socket
SetReadBuffer(bytes int) error
SetWriteBuffer(bytes int) error
+ ReadBuffer() (int, error)
+ WriteBuffer() (int, error)
}
// SetReadBuffer sets the size of the operating system's receive buffer
// associated with the Conn.
func (c *Conn) SetReadBuffer(bytes int) error {
- conn, ok := c.sock.(bufferSetter)
+ conn, ok := c.sock.(bufferedSocket)
if !ok {
return notSupported("set-read-buffer")
}
@@ -455,7 +458,7 @@ func (c *Conn) SetReadBuffer(bytes int) error {
// SetWriteBuffer sets the size of the operating system's transmit buffer
// associated with the Conn.
func (c *Conn) SetWriteBuffer(bytes int) error {
- conn, ok := c.sock.(bufferSetter)
+ conn, ok := c.sock.(bufferedSocket)
if !ok {
return notSupported("set-write-buffer")
}
@@ -463,6 +466,44 @@ func (c *Conn) SetWriteBuffer(bytes int) error {
return newOpError("set-write-buffer", conn.SetWriteBuffer(bytes))
}
+// ReadBuffer reads the size of the operating system's receive buffer
+// associated with the Conn.
+func (c *Conn) ReadBuffer() (int, error) {
+ conn, ok := c.sock.(bufferedSocket)
+ if !ok {
+ return 0, notSupported("get-read-buffer")
+ }
+
+ buff, err := conn.ReadBuffer()
+ if err != nil {
+ return 0, newOpError("get-read-buffer", err)
+ }
+ return buff, nil
+}
+
+// WriteBuffer reads the size of the operating system's transmit buffer
+// associated with the Conn.
+func (c *Conn) WriteBuffer() (int, error) {
+ conn, ok := c.sock.(bufferedSocket)
+ if !ok {
+ return 0, notSupported("get-write-buffer")
+ }
+
+ buff, err := conn.WriteBuffer()
+ if err != nil {
+ return 0, newOpError("get-write-buffer", err)
+ }
+
+ return buff, nil
+}
+
+// PID returns the PID associated with the Conn. It is also known as
+// the port ID in netlink terminology.
+// https://docs.kernel.org/userspace-api/netlink/intro.html#nlmsg-pid
+func (c *Conn) PID() uint32 {
+ return c.pid
+}
+
// A syscallConner is a Socket that supports syscall.Conn.
type syscallConner interface {
Socket
diff --git a/vendor/github.com/mdlayher/netlink/conn_linux.go b/vendor/github.com/mdlayher/netlink/conn_linux.go
index 4af18c99a3..1eab74af5f 100644
--- a/vendor/github.com/mdlayher/netlink/conn_linux.go
+++ b/vendor/github.com/mdlayher/netlink/conn_linux.go
@@ -212,6 +212,14 @@ func (c *conn) SetReadBuffer(bytes int) error { return c.s.SetReadBuffer(bytes)
// associated with the Conn.
func (c *conn) SetWriteBuffer(bytes int) error { return c.s.SetWriteBuffer(bytes) }
+// ReadBuffer reads the size of the operating system's receive buffer
+// associated with the Conn.
+func (c *conn) ReadBuffer() (int, error) { return c.s.ReadBuffer() }
+
+// WriteBuffer reads the size of the operating system's transmit buffer
+// associated with the Conn.
+func (c *conn) WriteBuffer() (int, error) { return c.s.WriteBuffer() }
+
// SyscallConn returns a raw network connection.
func (c *conn) SyscallConn() (syscall.RawConn, error) { return c.s.SyscallConn() }
diff --git a/vendor/github.com/mdlayher/netlink/errors.go b/vendor/github.com/mdlayher/netlink/errors.go
index 8c0fce7e4d..e1fe0ab349 100644
--- a/vendor/github.com/mdlayher/netlink/errors.go
+++ b/vendor/github.com/mdlayher/netlink/errors.go
@@ -69,6 +69,11 @@ type OpError struct {
// is not set, both of these fields will be empty.
Message string
Offset int
+
+ // Sequence is the netlink message sequence number associated with the
+ // error. This field is only populated if the error was produced as the
+ // result of a netlink message; otherwise, it will be zero.
+ Sequence uint32
}
// newOpError is a small wrapper for creating an OpError. As a convenience, it
diff --git a/vendor/github.com/mdlayher/netlink/message.go b/vendor/github.com/mdlayher/netlink/message.go
index 57277165a3..6cfefd59c8 100644
--- a/vendor/github.com/mdlayher/netlink/message.go
+++ b/vendor/github.com/mdlayher/netlink/message.go
@@ -293,7 +293,8 @@ func checkMessage(m Message) error {
// Error code is a negative integer, convert it into an OS-specific raw
// system call error, but do not wrap with os.NewSyscallError to signify
// that this error was produced by a netlink message; not a system call.
- Err: newError(-1 * int(c)),
+ Err: newError(-1 * int(c)),
+ Sequence: m.Header.Sequence,
}
// TODO(mdlayher): investigate the Capped flag.
diff --git a/vendor/github.com/mdlayher/socket/.golangci.yml b/vendor/github.com/mdlayher/socket/.golangci.yml
new file mode 100644
index 0000000000..1f10166aab
--- /dev/null
+++ b/vendor/github.com/mdlayher/socket/.golangci.yml
@@ -0,0 +1,16 @@
+version: "2"
+linters:
+ enable:
+ - misspell
+ - modernize
+ - revive
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+formatters:
+ exclusions:
+ generated: lax
diff --git a/vendor/github.com/mdlayher/socket/CHANGELOG.md b/vendor/github.com/mdlayher/socket/CHANGELOG.md
index b83418532d..b94818e7ca 100644
--- a/vendor/github.com/mdlayher/socket/CHANGELOG.md
+++ b/vendor/github.com/mdlayher/socket/CHANGELOG.md
@@ -1,5 +1,10 @@
# CHANGELOG
+## v0.5.2
+
+- [Improvement]: Bump build to Go 1.23.0. Note this is required for the latest
+ Go extended library versions.
+
## v0.5.1
- [Improvement]: revert `go.mod` to Go 1.20 to [resolve an issue around Go
diff --git a/vendor/github.com/mdlayher/socket/accept4.go b/vendor/github.com/mdlayher/socket/accept4.go
index e1016b2063..48be812ed8 100644
--- a/vendor/github.com/mdlayher/socket/accept4.go
+++ b/vendor/github.com/mdlayher/socket/accept4.go
@@ -1,5 +1,4 @@
//go:build dragonfly || freebsd || illumos || linux
-// +build dragonfly freebsd illumos linux
package socket
diff --git a/vendor/github.com/mdlayher/socket/conn.go b/vendor/github.com/mdlayher/socket/conn.go
index 5be502f5a2..6057a2e0a8 100644
--- a/vendor/github.com/mdlayher/socket/conn.go
+++ b/vendor/github.com/mdlayher/socket/conn.go
@@ -120,7 +120,7 @@ func (c *Conn) ReadContext(ctx context.Context, b []byte) (int, error) {
b = b[:maxRW]
}
- n, err := readT(c, ctx, "read", func(fd int) (int, error) {
+ n, err := readT(ctx, c, "read", func(fd int) (int, error) {
return unix.Read(fd, b)
})
if n == 0 && err == nil && c.facts.zeroReadIsEOF {
@@ -142,12 +142,12 @@ func (c *Conn) WriteContext(ctx context.Context, b []byte) (int, error) {
)
doErr := c.write(ctx, "write", func(fd int) error {
- max := len(b)
- if c.facts.isStream && max-nn > maxRW {
- max = nn + maxRW
+ lenb := len(b)
+ if c.facts.isStream && lenb-nn > maxRW {
+ lenb = nn + maxRW
}
- n, err = unix.Write(fd, b[nn:max])
+ n, err = unix.Write(fd, b[nn:lenb])
if n > 0 {
nn += n
}
@@ -418,7 +418,7 @@ func (c *Conn) Accept(ctx context.Context, flags int) (*Conn, unix.Sockaddr, err
sa unix.Sockaddr
}
- r, err := readT(c, ctx, sysAccept, func(fd int) (ret, error) {
+ r, err := readT(ctx, c, sysAccept, func(fd int) (ret, error) {
// Either accept(2) or accept4(2) depending on the OS.
nfd, sa, err := accept(fd, flags|socketFlags)
return ret{nfd, sa}, err
@@ -464,7 +464,7 @@ func (c *Conn) Connect(ctx context.Context, sa unix.Sockaddr) (unix.Sockaddr, er
// have an explicit WaitWrite call like internal/poll does, so we have
// to wait until the runtime calls the closure again to indicate we can
// write.
- progress uint32
+ progress atomic.Uint32
// Capture closure sockaddr and error.
rsa unix.Sockaddr
@@ -472,7 +472,7 @@ func (c *Conn) Connect(ctx context.Context, sa unix.Sockaddr) (unix.Sockaddr, er
)
doErr := c.write(ctx, op, func(fd int) error {
- if atomic.AddUint32(&progress, 1) == 1 {
+ if progress.Add(1) == 1 {
// First call: initiate connect.
return unix.Connect(fd, sa)
}
@@ -569,7 +569,7 @@ func (c *Conn) Recvmsg(ctx context.Context, p, oob []byte, flags int) (int, int,
from unix.Sockaddr
}
- r, err := readT(c, ctx, "recvmsg", func(fd int) (ret, error) {
+ r, err := readT(ctx, c, "recvmsg", func(fd int) (ret, error) {
n, oobn, recvflags, from, err := unix.Recvmsg(fd, p, oob, flags)
return ret{n, oobn, recvflags, from}, err
})
@@ -587,7 +587,7 @@ func (c *Conn) Recvfrom(ctx context.Context, p []byte, flags int) (int, unix.Soc
addr unix.Sockaddr
}
- out, err := readT(c, ctx, "recvfrom", func(fd int) (ret, error) {
+ out, err := readT(ctx, c, "recvfrom", func(fd int) (ret, error) {
n, addr, err := unix.Recvfrom(fd, p, flags)
return ret{n, addr}, err
})
@@ -600,7 +600,7 @@ func (c *Conn) Recvfrom(ctx context.Context, p []byte, flags int) (int, unix.Soc
// Sendmsg wraps sendmsg(2).
func (c *Conn) Sendmsg(ctx context.Context, p, oob []byte, to unix.Sockaddr, flags int) (int, error) {
- return writeT(c, ctx, "sendmsg", func(fd int) (int, error) {
+ return writeT(ctx, c, "sendmsg", func(fd int) (int, error) {
return unix.SendmsgN(fd, p, oob, to, flags)
})
}
@@ -645,7 +645,7 @@ func (c *Conn) Shutdown(how int) error {
// read wraps readT to execute a function and capture its error result. This is
// a convenience wrapper for functions which don't return any extra values.
func (c *Conn) read(ctx context.Context, op string, f func(fd int) error) error {
- _, err := readT(c, ctx, op, func(fd int) (struct{}, error) {
+ _, err := readT(ctx, c, op, func(fd int) (struct{}, error) {
return struct{}{}, f(fd)
})
return err
@@ -654,7 +654,7 @@ func (c *Conn) read(ctx context.Context, op string, f func(fd int) error) error
// write executes f, a write function, against the associated file descriptor.
// op is used to create an *os.SyscallError if the file descriptor is closed.
func (c *Conn) write(ctx context.Context, op string, f func(fd int) error) error {
- _, err := writeT(c, ctx, op, func(fd int) (struct{}, error) {
+ _, err := writeT(ctx, c, op, func(fd int) (struct{}, error) {
return struct{}{}, f(fd)
})
return err
@@ -662,7 +662,7 @@ func (c *Conn) write(ctx context.Context, op string, f func(fd int) error) error
// readT executes c.rc.Read for op using the input function, returning a newly
// allocated result T.
-func readT[T any](c *Conn, ctx context.Context, op string, f func(fd int) (T, error)) (T, error) {
+func readT[T any](ctx context.Context, c *Conn, op string, f func(fd int) (T, error)) (T, error) {
return rwT(c, rwContext[T]{
Context: ctx,
Type: read,
@@ -673,7 +673,7 @@ func readT[T any](c *Conn, ctx context.Context, op string, f func(fd int) (T, er
// writeT executes c.rc.Write for op using the input function, returning a newly
// allocated result T.
-func writeT[T any](c *Conn, ctx context.Context, op string, f func(fd int) (T, error)) (T, error) {
+func writeT[T any](ctx context.Context, c *Conn, op string, f func(fd int) (T, error)) (T, error) {
return rwT(c, rwContext[T]{
Context: ctx,
Type: write,
@@ -771,9 +771,7 @@ func rwT[T any](c *Conn, rw rwContext[T]) (T, error) {
//
// TODO(mdlayher): is it possible to detect a background context vs a
// context with possible future cancel?
- wg.Add(1)
- go func() {
- defer wg.Done()
+ wg.Go(func() {
select {
case <-rw.Context.Done():
@@ -784,7 +782,7 @@ func rwT[T any](c *Conn, rw rwContext[T]) (T, error) {
case <-doneC:
// Nothing to do.
}
- }()
+ })
}
var (
diff --git a/vendor/github.com/mdlayher/socket/conn_linux.go b/vendor/github.com/mdlayher/socket/conn_linux.go
index 081194f327..b1cdffbdc6 100644
--- a/vendor/github.com/mdlayher/socket/conn_linux.go
+++ b/vendor/github.com/mdlayher/socket/conn_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package socket
diff --git a/vendor/github.com/mdlayher/socket/netns_linux.go b/vendor/github.com/mdlayher/socket/netns_linux.go
index b29115ad1c..9f37b77029 100644
--- a/vendor/github.com/mdlayher/socket/netns_linux.go
+++ b/vendor/github.com/mdlayher/socket/netns_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package socket
@@ -65,7 +64,7 @@ func withNetNS(fd int, fn func() (*Conn, error)) (*Conn, error) {
// No more thread-local state manipulation; return the new Conn.
runtime.UnlockOSThread()
conn = c
- return nil
+ return err
})
if err := eg.Wait(); err != nil {
diff --git a/vendor/github.com/mdlayher/socket/setbuffer_linux.go b/vendor/github.com/mdlayher/socket/setbuffer_linux.go
index 0d4aa4417c..ae631893a6 100644
--- a/vendor/github.com/mdlayher/socket/setbuffer_linux.go
+++ b/vendor/github.com/mdlayher/socket/setbuffer_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package socket
diff --git a/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go b/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go
index 40e834310b..f4a7e559b3 100644
--- a/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go
+++ b/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go
@@ -1,5 +1,4 @@
//go:build !darwin
-// +build !darwin
package socket
diff --git a/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go b/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go
index 8547c8dfd1..820bf436ab 100644
--- a/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go
+++ b/vendor/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header/header.go
@@ -90,7 +90,7 @@ loop:
s = skipSpace(s[1:])
}
}
- return
+ return specs
}
func skipSpace(s string) (rest string) {
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_go116.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_go116.go
deleted file mode 100644
index effc57840a..0000000000
--- a/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_go116.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//go:build !go1.17
-// +build !go1.17
-
-package collectors
-
-import "github.com/prometheus/client_golang/prometheus"
-
-// NewGoCollector returns a collector that exports metrics about the current Go
-// process. This includes memory stats. To collect those, runtime.ReadMemStats
-// is called. This requires to “stop the world”, which usually only happens for
-// garbage collection (GC). Take the following implications into account when
-// deciding whether to use the Go collector:
-//
-// 1. The performance impact of stopping the world is the more relevant the more
-// frequently metrics are collected. However, with Go1.9 or later the
-// stop-the-world time per metrics collection is very short (~25µs) so that the
-// performance impact will only matter in rare cases. However, with older Go
-// versions, the stop-the-world duration depends on the heap size and can be
-// quite significant (~1.7 ms/GiB as per
-// https://go-review.googlesource.com/c/go/+/34937).
-//
-// 2. During an ongoing GC, nothing else can stop the world. Therefore, if the
-// metrics collection happens to coincide with GC, it will only complete after
-// GC has finished. Usually, GC is fast enough to not cause problems. However,
-// with a very large heap, GC might take multiple seconds, which is enough to
-// cause scrape timeouts in common setups. To avoid this problem, the Go
-// collector will use the memstats from a previous collection if
-// runtime.ReadMemStats takes more than 1s. However, if there are no previously
-// collected memstats, or their collection is more than 5m ago, the collection
-// will block until runtime.ReadMemStats succeeds.
-//
-// NOTE: The problem is solved in Go 1.15, see
-// https://github.com/golang/go/issues/19812 for the related Go issue.
-func NewGoCollector() prometheus.Collector {
- return prometheus.NewGoCollector()
-}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go
index cc4ef1077e..d29ade654f 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector_latest.go
@@ -90,13 +90,13 @@ func WithGoCollectorMemStatsMetricsDisabled() func(options *internal.GoCollector
// GoRuntimeMetricsRule allow enabling and configuring particular group of runtime/metrics.
// TODO(bwplotka): Consider adding ability to adjust buckets.
type GoRuntimeMetricsRule struct {
- // Matcher represents RE2 expression will match the runtime/metrics from https://golang.bg/src/runtime/metrics/description.go
+ // Matcher represents RE2 expression will match the runtime/metrics from https://pkg.go.dev/runtime/metrics
// Use `regexp.MustCompile` or `regexp.Compile` to create this field.
Matcher *regexp.Regexp
}
// WithGoCollectorRuntimeMetrics allows enabling and configuring particular group of runtime/metrics.
-// See the list of metrics https://golang.bg/src/runtime/metrics/description.go (pick the Go version you use there!).
+// See the list of metrics https://pkg.go.dev/runtime/metrics (pick the Go version you use there!).
// You can use this option in repeated manner, which will add new rules. The order of rules is important, the last rule
// that matches particular metrics is applied.
func WithGoCollectorRuntimeMetrics(rules ...GoRuntimeMetricsRule) func(options *internal.GoCollectorOptions) {
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go
index 4ce84e7a80..7d963d3afb 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go
@@ -85,11 +85,12 @@ type CounterVecOpts struct {
// Both internal tracking values are added up in the Write method. This has to
// be taken into account when it comes to precision and overflow behavior.
func NewCounter(opts CounterOpts) Counter {
- desc := NewDesc(
+ desc := V2.NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.Help,
- nil,
+ UnconstrainedLabels(nil),
opts.ConstLabels,
+ WithUnit(opts.Unit),
)
if opts.now == nil {
opts.now = time.Now
@@ -205,6 +206,7 @@ func (v2) NewCounterVec(opts CounterVecOpts) *CounterVec {
opts.Help,
opts.VariableLabels,
opts.ConstLabels,
+ WithUnit(opts.Unit),
)
if opts.now == nil {
opts.now = time.Now
@@ -349,10 +351,11 @@ type CounterFunc interface {
//
// Check out the ExampleGaugeFunc examples for the similar GaugeFunc.
func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
- return newValueFunc(NewDesc(
+ return newValueFunc(V2.NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.Help,
- nil,
+ UnconstrainedLabels(nil),
opts.ConstLabels,
+ WithUnit(opts.Unit),
), CounterValue, function)
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go
index 2331b8b4f3..a3c92e7a4c 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go
@@ -47,6 +47,8 @@ type Desc struct {
fqName string
// help provides some helpful information about this metric.
help string
+ // unit provides the unit of this metric.
+ unit string
// constLabelPairs contains precalculated DTO label pairs based on
// the constant labels.
constLabelPairs []*dto.LabelPair
@@ -66,6 +68,16 @@ type Desc struct {
err error
}
+// DescOpt allows setting optional fields for NewDesc.
+type DescOpt func(*Desc)
+
+// WithUnit sets the unit for a Desc.
+func WithUnit(unit string) DescOpt {
+ return func(d *Desc) {
+ d.unit = unit
+ }
+}
+
// NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc
// and will be reported on registration time. variableLabels and constLabels can
// be nil if no such labels should be set. fqName must not be empty.
@@ -89,14 +101,17 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
//
// For constLabels, the label values are constant. Therefore, they are fully
// specified in the Desc. See the Collector example for a usage pattern.
-func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc {
+func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels, opts ...DescOpt) *Desc {
d := &Desc{
fqName: fqName,
help: help,
variableLabels: variableLabels.compile(),
}
- //nolint:staticcheck // TODO: Don't use deprecated model.NameValidationScheme.
- if !model.NameValidationScheme.IsValidMetricName(fqName) {
+
+ for _, opt := range opts {
+ opt(d)
+ }
+ if !model.UTF8Validation.IsValidMetricName(fqName) {
d.err = fmt.Errorf("%q is not a valid metric name", fqName)
return d
}
@@ -150,11 +165,13 @@ func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, const
d.id = xxh.Sum64()
// Sort labelNames so that order doesn't matter for the hash.
sort.Strings(labelNames)
- // Now hash together (in this order) the help string and the sorted
+ // Now hash together (in this order) the help string, the unit string and the sorted
// label names.
xxh.Reset()
xxh.WriteString(help)
xxh.Write(separatorByteSlice)
+ xxh.WriteString(d.unit)
+ xxh.Write(separatorByteSlice)
for _, labelName := range labelNames {
xxh.WriteString(labelName)
xxh.Write(separatorByteSlice)
@@ -182,6 +199,15 @@ func NewInvalidDesc(err error) *Desc {
}
}
+// Err returns an error that occurred during construction, if any.
+//
+// Calling this method is optional. It can be used to detect construction
+// errors early, before invoking other methods on the Desc. If an error is
+// present, later operations may not behave as expected.
+func (d *Desc) Err() error {
+ return d.err
+}
+
func (d *Desc) String() string {
lpStrings := make([]string, 0, len(d.constLabelPairs))
for _, lp := range d.constLabelPairs {
@@ -202,9 +228,10 @@ func (d *Desc) String() string {
}
}
return fmt.Sprintf(
- "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: {%s}}",
+ "Desc{fqName: %q, help: %q, unit: %q, constLabels: {%s}, variableLabels: {%s}}",
d.fqName,
d.help,
+ d.unit,
strings.Join(lpStrings, ","),
strings.Join(vlStrings, ","),
)
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
index de5a856293..327746f433 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
@@ -47,14 +47,14 @@ func (e *expvarCollector) Collect(ch chan<- Metric) {
if expVar == nil {
continue
}
- var v interface{}
+ var v any
labels := make([]string, len(desc.variableLabels.names))
if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil {
ch <- NewInvalidMetric(desc, err)
continue
}
- var processValue func(v interface{}, i int)
- processValue = func(v interface{}, i int) {
+ var processValue func(v any, i int)
+ processValue = func(v any, i int) {
if i >= len(labels) {
copiedLabels := append(make([]string, 0, len(labels)), labels...)
switch v := v.(type) {
@@ -72,7 +72,7 @@ func (e *expvarCollector) Collect(ch chan<- Metric) {
ch <- m
return
}
- vm, ok := v.(map[string]interface{})
+ vm, ok := v.(map[string]any)
if !ok {
return
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go
index dd2eac9406..41e54bf270 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go
@@ -76,11 +76,12 @@ type GaugeVecOpts struct {
// scenarios for Gauges and Counters, where the former tends to be Set-heavy and
// the latter Inc-heavy.
func NewGauge(opts GaugeOpts) Gauge {
- desc := NewDesc(
+ desc := V2.NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.Help,
- nil,
+ UnconstrainedLabels(nil),
opts.ConstLabels,
+ WithUnit(opts.Unit),
)
result := &gauge{desc: desc, labelPairs: desc.constLabelPairs}
result.init(result) // Init self-collection.
@@ -163,6 +164,7 @@ func (v2) NewGaugeVec(opts GaugeVecOpts) *GaugeVec {
opts.Help,
opts.VariableLabels,
opts.ConstLabels,
+ WithUnit(opts.Unit),
)
return &GaugeVec{
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
@@ -302,10 +304,11 @@ type GaugeFunc interface {
// value of 1. Example:
// https://github.com/prometheus/common/blob/8558a5b7db3c84fa38b4766966059a7bd5bfa2ee/version/info.go#L36-L56
func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc {
- return newValueFunc(NewDesc(
+ return newValueFunc(V2.NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.Help,
- nil,
+ UnconstrainedLabels(nil),
opts.ConstLabels,
+ WithUnit(opts.Unit),
), GaugeValue, function)
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go
deleted file mode 100644
index 897a6e906b..0000000000
--- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2021 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//go:build !go1.17
-// +build !go1.17
-
-package prometheus
-
-import (
- "runtime"
- "sync"
- "time"
-)
-
-type goCollector struct {
- base baseGoCollector
-
- // ms... are memstats related.
- msLast *runtime.MemStats // Previously collected memstats.
- msLastTimestamp time.Time
- msMtx sync.Mutex // Protects msLast and msLastTimestamp.
- msMetrics memStatsMetrics
- msRead func(*runtime.MemStats) // For mocking in tests.
- msMaxWait time.Duration // Wait time for fresh memstats.
- msMaxAge time.Duration // Maximum allowed age of old memstats.
-}
-
-// NewGoCollector is the obsolete version of collectors.NewGoCollector.
-// See there for documentation.
-//
-// Deprecated: Use collectors.NewGoCollector instead.
-func NewGoCollector() Collector {
- msMetrics := goRuntimeMemStats()
- msMetrics = append(msMetrics, struct {
- desc *Desc
- eval func(*runtime.MemStats) float64
- valType ValueType
- }{
- // This metric is omitted in Go1.17+, see https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
- desc: NewDesc(
- memstatNamespace("gc_cpu_fraction"),
- "The fraction of this program's available CPU time used by the GC since the program started.",
- nil, nil,
- ),
- eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
- valType: GaugeValue,
- })
- return &goCollector{
- base: newBaseGoCollector(),
- msLast: &runtime.MemStats{},
- msRead: runtime.ReadMemStats,
- msMaxWait: time.Second,
- msMaxAge: 5 * time.Minute,
- msMetrics: msMetrics,
- }
-}
-
-// Describe returns all descriptions of the collector.
-func (c *goCollector) Describe(ch chan<- *Desc) {
- c.base.Describe(ch)
- for _, i := range c.msMetrics {
- ch <- i.desc
- }
-}
-
-// Collect returns the current state of all metrics of the collector.
-func (c *goCollector) Collect(ch chan<- Metric) {
- var (
- ms = &runtime.MemStats{}
- done = make(chan struct{})
- )
- // Start reading memstats first as it might take a while.
- go func() {
- c.msRead(ms)
- c.msMtx.Lock()
- c.msLast = ms
- c.msLastTimestamp = time.Now()
- c.msMtx.Unlock()
- close(done)
- }()
-
- // Collect base non-memory metrics.
- c.base.Collect(ch)
-
- timer := time.NewTimer(c.msMaxWait)
- select {
- case <-done: // Our own ReadMemStats succeeded in time. Use it.
- timer.Stop() // Important for high collection frequencies to not pile up timers.
- c.msCollect(ch, ms)
- return
- case <-timer.C: // Time out, use last memstats if possible. Continue below.
- }
- c.msMtx.Lock()
- if time.Since(c.msLastTimestamp) < c.msMaxAge {
- // Last memstats are recent enough. Collect from them under the lock.
- c.msCollect(ch, c.msLast)
- c.msMtx.Unlock()
- return
- }
- // If we are here, the last memstats are too old or don't exist. We have
- // to wait until our own ReadMemStats finally completes. For that to
- // happen, we have to release the lock.
- c.msMtx.Unlock()
- <-done
- c.msCollect(ch, ms)
-}
-
-func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) {
- for _, i := range c.msMetrics {
- ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
- }
-}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go
index 6b8684731c..1db1c4be09 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go
@@ -98,7 +98,7 @@ type goCollector struct {
// snapshot is always produced by Collect.
mu sync.Mutex
- // Contains all samples that has to retrieved from runtime/metrics (not all of them will be exposed).
+ // Contains all samples that have to be retrieved from runtime/metrics (not all of them will be exposed).
sampleBuf []metrics.Sample
// sampleMap allows lookup for MemStats metrics and runtime/metrics histograms for exact sums.
sampleMap map[string]*metrics.Sample
@@ -210,16 +210,26 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]
+ // Extract unit from the runtime/metrics name (e.g., "/gc/heap/allocs:bytes" -> "bytes")
+ // and sanitize to match Prometheus naming conventions (e.g., "cpu-seconds" -> "cpu_seconds")
+ var unit string
+ if idx := strings.IndexRune(d.Name, ':'); idx >= 0 {
+ unit = d.Name[idx+1:]
+ unit = strings.ReplaceAll(unit, "-", "_")
+ unit = strings.ReplaceAll(unit, "*", "_")
+ unit = strings.ReplaceAll(unit, "/", "_per_")
+ }
+
var m collectorMetric
if d.Kind == metrics.KindFloat64Histogram {
_, hasSum := opt.RuntimeMetricSumForHist[d.Name]
- unit := d.Name[strings.IndexRune(d.Name, ':')+1:]
m = newBatchHistogram(
- NewDesc(
+ V2.NewDesc(
BuildFQName(namespace, subsystem, name),
help,
+ UnconstrainedLabels(nil),
nil,
- nil,
+ WithUnit(unit),
),
internal.RuntimeMetricsBucketsForUnit(bucketsMap[d.Name], unit),
hasSum,
@@ -230,6 +240,7 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
Subsystem: subsystem,
Name: name,
Help: help,
+ Unit: unit,
},
)
} else {
@@ -238,6 +249,7 @@ func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
Subsystem: subsystem,
Name: name,
Help: help,
+ Unit: unit,
})
}
metricSet = append(metricSet, m)
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go
index c453b754a7..88bae3b32c 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go
@@ -378,6 +378,9 @@ type HistogramOpts struct {
// string.
Help string
+ // Unit provides the unit of this Histogram.
+ Unit string
+
// ConstLabels are used to attach fixed labels to this metric. Metrics
// with the same fully-qualified name must have the same label names in
// their ConstLabels.
@@ -522,11 +525,12 @@ type HistogramVecOpts struct {
// for each bucket.
func NewHistogram(opts HistogramOpts) Histogram {
return newHistogram(
- NewDesc(
+ V2.NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.Help,
- nil,
+ UnconstrainedLabels(nil),
opts.ConstLabels,
+ WithUnit(opts.Unit),
),
opts,
)
@@ -966,7 +970,7 @@ func (h *histogram) maybeReset(
// We are using the possibly mocked h.now() rather than
// time.Since(h.lastResetTime) to enable testing.
if h.nativeHistogramMinResetDuration == 0 || // No reset configured.
- h.resetScheduled || // Do not interefere if a reset is already scheduled.
+ h.resetScheduled || // Do not interfere if a reset is already scheduled.
h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration {
return false
}
@@ -1053,8 +1057,8 @@ func (h *histogram) maybeWidenZeroBucket(hot, cold *histogramCounts) bool {
atomic.StoreUint64(&cold.nativeHistogramZeroThresholdBits, math.Float64bits(newZeroThreshold))
// ...and then merge the newly deleted buckets into the wider zero
// bucket.
- mergeAndDeleteOrAddAndReset := func(hotBuckets, coldBuckets *sync.Map) func(k, v interface{}) bool {
- return func(k, v interface{}) bool {
+ mergeAndDeleteOrAddAndReset := func(hotBuckets, coldBuckets *sync.Map) func(k, v any) bool {
+ return func(k, v any) bool {
key := k.(int)
bucket := v.(*int64)
if key == smallestKey {
@@ -1107,8 +1111,8 @@ func (h *histogram) doubleBucketWidth(hot, cold *histogramCounts) {
// ...adjust the schema in the cold counts, too...
atomic.StoreInt32(&cold.nativeHistogramSchema, coldSchema)
// ...and then merge the cold buckets into the wider hot buckets.
- merge := func(hotBuckets *sync.Map) func(k, v interface{}) bool {
- return func(k, v interface{}) bool {
+ merge := func(hotBuckets *sync.Map) func(k, v any) bool {
+ return func(k, v any) bool {
key := k.(int)
bucket := v.(*int64)
// Adjust key to match the bucket to merge into.
@@ -1190,6 +1194,7 @@ func (v2) NewHistogramVec(opts HistogramVecOpts) *HistogramVec {
opts.Help,
opts.VariableLabels,
opts.ConstLabels,
+ WithUnit(opts.Unit),
)
return &HistogramVec{
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
@@ -1476,7 +1481,7 @@ func pickSchema(bucketFactor float64) int32 {
func makeBuckets(buckets *sync.Map) ([]*dto.BucketSpan, []int64) {
var ii []int
- buckets.Range(func(k, v interface{}) bool {
+ buckets.Range(func(k, v any) bool {
ii = append(ii, k.(int))
return true
})
@@ -1553,8 +1558,8 @@ func addToBucket(buckets *sync.Map, key int, increment int64) bool {
// according to the buckets ranged through. It then resets all buckets ranged
// through to 0 (but leaves them in place so that they don't need to get
// recreated on the next scrape).
-func addAndReset(hotBuckets *sync.Map, bucketNumber *uint32) func(k, v interface{}) bool {
- return func(k, v interface{}) bool {
+func addAndReset(hotBuckets *sync.Map, bucketNumber *uint32) func(k, v any) bool {
+ return func(k, v any) bool {
bucket := v.(*int64)
if addToBucket(hotBuckets, k.(int), atomic.LoadInt64(bucket)) {
atomic.AddUint32(bucketNumber, 1)
@@ -1565,7 +1570,7 @@ func addAndReset(hotBuckets *sync.Map, bucketNumber *uint32) func(k, v interface
}
func deleteSyncMap(m *sync.Map) {
- m.Range(func(k, v interface{}) bool {
+ m.Range(func(k, v any) bool {
m.Delete(k)
return true
})
@@ -1573,7 +1578,7 @@ func deleteSyncMap(m *sync.Map) {
func findSmallestKey(m *sync.Map) int {
result := math.MaxInt32
- m.Range(func(k, v interface{}) bool {
+ m.Range(func(k, v any) bool {
key := k.(int)
if key < result {
result = key
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go
index 7bac0da33d..2db270f216 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go
@@ -78,7 +78,7 @@ type OpCode struct {
// notion, pairing up elements that appear uniquely in each sequence.
// That, and the method here, appear to yield more intuitive difference
// reports than does diff. This method appears to be the least vulnerable
-// to synching up on blocks of "junk lines", though (like blank lines in
+// to syncing up on blocks of "junk lines", though (like blank lines in
// ordinary text files, or maybe "" lines in HTML files). That may be
// because this is the only method of the 3 that has a *concept* of
// "junk" .
@@ -567,7 +567,7 @@ type UnifiedDiff struct {
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
buf := bufio.NewWriter(writer)
defer buf.Flush()
- wf := func(format string, args ...interface{}) error {
+ wf := func(format string, args ...any) error {
_, err := fmt.Fprintf(buf, format, args...)
return err
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/labels.go b/vendor/github.com/prometheus/client_golang/prometheus/labels.go
index 5fe8d3b4d2..a0285489a0 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/labels.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/labels.go
@@ -184,6 +184,5 @@ func validateLabelValues(vals []string, expectedNumberOfValues int) error {
}
func checkLabelName(l string) bool {
- //nolint:staticcheck // TODO: Don't use deprecated model.NameValidationScheme.
- return model.NameValidationScheme.IsValidLabelName(l) && !strings.HasPrefix(l, reservedLabelPrefix)
+ return model.UTF8Validation.IsValidLabelName(l) && !strings.HasPrefix(l, reservedLabelPrefix)
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go
index 76e59f1288..c5cb90adf8 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/metric.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/metric.go
@@ -81,6 +81,9 @@ type Opts struct {
// string.
Help string
+ // Unit provides the unit of this metric as per https://prometheus.io/docs/specs/om
+ Unit string
+
// ConstLabels are used to attach fixed labels to this metric. Metrics
// with the same fully-qualified name must have the same label names in
// their ConstLabels.
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go
index b32c95fa3f..2b16298f40 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_darwin.go
@@ -72,7 +72,13 @@ func getOpenFileCount() (float64, error) {
}
func (c *processCollector) processCollect(ch chan<- Metric) {
- if procs, err := unix.SysctlKinfoProcSlice("kern.proc.pid", os.Getpid()); err == nil {
+ pid, err := c.pidFn()
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+
+ if procs, err := unix.SysctlKinfoProcSlice("kern.proc.pid", pid); err == nil {
if len(procs) == 1 {
startTime := float64(procs[0].Proc.P_starttime.Nano() / 1e9)
ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime)
@@ -84,6 +90,11 @@ func (c *processCollector) processCollect(ch chan<- Metric) {
c.reportError(ch, c.startTime, err)
}
+ if pid != os.Getpid() {
+ c.reportError(ch, nil, fmt.Errorf("collecting metrics for pid %d is not supported on darwin: process metrics collection is limited to the current process (pid %d)", pid, os.Getpid()))
+ return
+ }
+
// The proc structure returned by kern.proc.pid above has an Rusage member,
// but it is not filled in, so it needs to be fetched by getrusage(2). For
// that call, the UTime, STime, and Maxrss members are filled out, but not
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_windows.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_windows.go
index fa474289ef..c08dd05f03 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_windows.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_windows.go
@@ -30,6 +30,10 @@ var (
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount")
+
+ openProcess = windows.OpenProcess
+ closeHandle = windows.CloseHandle
+ getProcessTimes = windows.GetProcessTimes
)
type processMemoryCounters struct {
@@ -79,10 +83,21 @@ func getProcessHandleCount(handle windows.Handle) (uint32, error) {
}
func (c *processCollector) processCollect(ch chan<- Metric) {
- h := windows.CurrentProcess()
+ pid, err := c.pidFn()
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+
+ h, err := openProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, uint32(pid))
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+ defer closeHandle(h)
var startTime, exitTime, kernelTime, userTime windows.Filetime
- err := windows.GetProcessTimes(h, &startTime, &exitTime, &kernelTime, &userTime)
+ err = getProcessTimes(h, &startTime, &exitTime, &kernelTime, &userTime)
if err != nil {
c.reportError(ch, nil, err)
return
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
index 763d99e362..368625c6a8 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
@@ -37,10 +37,12 @@ import (
"fmt"
"io"
"net/http"
+ "slices"
"strconv"
"sync"
"time"
+ dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/expfmt"
"github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil"
@@ -74,11 +76,118 @@ func defaultCompressionFormats() []Compression {
}
var gzipPool = sync.Pool{
- New: func() interface{} {
+ New: func() any {
return gzip.NewWriter(nil)
},
}
+// coalescingGatherer wraps a TransactionalGatherer to deduplicate concurrent
+// Gather calls. When a Gather is already in flight, new callers join the
+// existing cycle and receive the same result once it completes. The underlying
+// done function is called exactly once, when the last joined caller releases.
+//
+// This prevents goroutine pile-up when the scrape rate is faster than the
+// time collectors need to produce metrics.
+type coalescingGatherer struct {
+ g prometheus.TransactionalGatherer
+ mu sync.Mutex
+ cycle *gatherCycle
+}
+
+// gatherCycle tracks a single in-flight Gather and all HTTP handlers sharing it.
+type gatherCycle struct {
+ ready chan struct{} // closed when Gather completes; happens-before reads of mfs/err/done
+ mfs []*dto.MetricFamily // canonical result, set before ready is closed; callers get a slices.Clone, the element values stay shared and must not be mutated
+ err error // set before ready is closed
+ done func() // underlying done callback; set before ready is closed
+ refs int // number of handlers using this cycle; protected by coalescingGatherer.mu
+}
+
+var _ prometheus.TransactionalGatherer = (*coalescingGatherer)(nil) // compile-time interface check
+
+// errGatherPanicked is returned to callers that joined an in-flight coalesced
+// Gather whose underlying gatherer panicked. See the panic guard in Gather for
+// why joiners receive this error instead of the panic itself.
+var errGatherPanicked = errors.New("coalesced gather panicked")
+
+func (c *coalescingGatherer) Gather() ([]*dto.MetricFamily, func(), error) {
+ c.mu.Lock()
+ if cy := c.cycle; cy != nil {
+ // c.cycle is non-nil while Gather runs or handlers are still consuming its results.
+ cy.refs++
+ c.mu.Unlock()
+ <-cy.ready
+ // Each caller gets its own slice header so it can filter or reorder
+ // without racing other callers sharing this cycle. The *dto.MetricFamily
+ // values remain shared and must not be mutated in place.
+ return slices.Clone(cy.mfs), c.releaseFunc(cy), cy.err
+ }
+ cy := &gatherCycle{
+ ready: make(chan struct{}),
+ done: func() {},
+ refs: 1,
+ }
+ c.cycle = cy
+ c.mu.Unlock()
+
+ // Guard against a panic in c.g.Gather. The common case, a panicking
+ // Collector, never reaches here: Registry.Gather recovers Collector panics
+ // and returns them as an error. This guard only covers the rare case where
+ // the wrapped gatherer itself panics.
+ //
+ // We deliberately do not recover: the leader's panic propagates and is
+ // handled by net/http exactly as it would be without coalescing. We only
+ // set cy.err before closing cy.ready so joiners waiting on <-cy.ready fail
+ // with that error instead of silently returning an empty, successful
+ // response, and we clear c.cycle so the next Gather starts a fresh cycle.
+ //
+ // The leader never runs its own releaseFunc on this path, so its ref is
+ // not decremented; that is harmless because the cycle is detached (c.cycle
+ // = nil) and cy.done is still the no-op set at construction (c.g.Gather
+ // panicked before assigning a real done). If cy.done is ever made non-nil
+ // before c.g.Gather runs, this path would need to release it.
+ panicked := true
+ defer func() {
+ if panicked {
+ c.mu.Lock()
+ if c.cycle == cy {
+ c.cycle = nil
+ }
+ c.mu.Unlock()
+ cy.err = errGatherPanicked // set before close: happens-before joiners' reads
+ close(cy.ready)
+ }
+ }()
+ cy.mfs, cy.done, cy.err = c.g.Gather()
+ panicked = false
+ close(cy.ready) // happens-before joiners' reads of cy.mfs/err/done
+
+ // Clone here too so cy.mfs stays the write-once canonical slice: joiners
+ // read it concurrently via slices.Clone, so the leader must not hand out
+ // (and potentially reorder) the same backing array.
+ return slices.Clone(cy.mfs), c.releaseFunc(cy), cy.err
+}
+
+// releaseFunc returns the done callback for one caller sharing cy.
+// When the last caller releases, the underlying done is invoked and the
+// cycle is cleared so the next Gather starts fresh.
+func (c *coalescingGatherer) releaseFunc(cy *gatherCycle) func() {
+ return func() {
+ c.mu.Lock()
+ cy.refs--
+ if cy.refs > 0 {
+ c.mu.Unlock()
+ return
+ }
+ // Last caller.
+ if c.cycle == cy {
+ c.cycle = nil
+ }
+ c.mu.Unlock()
+ cy.done() // called outside the lock to avoid holding it during done
+ }
+}
+
// Handler returns an http.Handler for the prometheus.DefaultGatherer, using
// default HandlerOpts, i.e. it reports the first error as an HTTP error, it has
// no error logging, and it applies compression if requested by the client.
@@ -89,6 +198,10 @@ var gzipPool = sync.Pool{
// metrics used for instrumentation will be shared between them, providing
// global scrape counts.
//
+// The handler supports filtering metrics by name using the `name[]` query parameter.
+// Multiple metric names can be specified by providing the parameter multiple times.
+// When no name[] parameters are provided, all metrics are returned.
+//
// This function is meant to cover the bulk of basic use cases. If you are doing
// anything that requires more customization (including using a non-default
// Gatherer, different instrumentation, and non-default HandlerOpts), use the
@@ -105,6 +218,10 @@ func Handler() http.Handler {
// Gatherers, with non-default HandlerOpts, and/or with custom (or no)
// instrumentation. Use the InstrumentMetricHandler function to apply the same
// kind of instrumentation as it is used by the Handler function.
+//
+// The handler supports filtering metrics by name using the `name[]` query parameter.
+// Multiple metric names can be specified by providing the parameter multiple times.
+// When no name[] parameters are provided, all metrics are returned.
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
return HandlerForTransactional(prometheus.ToTransactionalGatherer(reg), opts)
}
@@ -112,7 +229,15 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
// HandlerForTransactional is like HandlerFor, but it uses transactional gather, which
// can safely change in-place returned *dto.MetricFamily before call to `Gather` and after
// call to `done` of that `Gather`.
+//
+// The handler supports filtering metrics by name using the `name[]` query parameter.
+// Multiple metric names can be specified by providing the parameter multiple times.
+// When no name[] parameters are provided, all metrics are returned.
func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerOpts) http.Handler {
+ if opts.CoalesceGather {
+ reg = &coalescingGatherer{g: reg}
+ }
+
var (
inFlightSem chan struct{}
errCnt = prometheus.NewCounterVec(
@@ -214,12 +339,14 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
rsp.Header().Set(contentEncodingHeader, encodingHeader)
}
- var enc expfmt.Encoder
+ var (
+ enc expfmt.Encoder
+ encOpts []expfmt.EncoderOption
+ )
if opts.EnableOpenMetricsTextCreatedSamples {
- enc = expfmt.NewEncoder(w, contentType, expfmt.WithCreatedLines())
- } else {
- enc = expfmt.NewEncoder(w, contentType)
+ encOpts = append(encOpts, expfmt.WithCreatedLines())
}
+ enc = expfmt.NewEncoder(w, contentType, encOpts...)
// handleError handles the error according to opts.ErrorHandling
// and returns true if we have to abort after the handling.
@@ -245,7 +372,21 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
return false
}
+ // Build metric name filter set from query params (if any)
+ var metricFilter map[string]struct{}
+ if metricNames := req.URL.Query()["name[]"]; len(metricNames) > 0 {
+ metricFilter = make(map[string]struct{}, len(metricNames))
+ for _, name := range metricNames {
+ metricFilter[name] = struct{}{}
+ }
+ }
+
for _, mf := range mfs {
+ if metricFilter != nil {
+ if _, ok := metricFilter[mf.GetName()]; !ok {
+ continue
+ }
+ }
if handleError(enc.Encode(mf)) {
return
}
@@ -353,7 +494,7 @@ const (
// log.Logger from the standard library implements this interface, and it is
// easy to implement by custom loggers, if they don't do so already anyway.
type Logger interface {
- Println(v ...interface{})
+ Println(v ...any)
}
// HandlerOpts specifies options how to serve metrics via an http.Handler. The
@@ -400,6 +541,40 @@ type HandlerOpts struct {
// Service Unavailable and a suitable message in the body. If
// MaxRequestsInFlight is 0 or negative, no limit is applied.
MaxRequestsInFlight int
+ // CoalesceGather, if true, deduplicates concurrent Gather calls so that
+ // only one collection runs at a time. Additional requests that arrive
+ // while a Gather is in flight will receive the same result once it
+ // completes. This prevents goroutine pile-up when the scrape rate is
+ // faster than the time collectors need to produce metrics.
+ //
+ // When enabled, concurrent scrapers share a single metric snapshot per
+ // collection cycle. Each request receives its own copy of the returned
+ // slice, so filtering or reordering it (for example via name[] query
+ // parameters) is safe. The pointed-to MetricFamily values are still
+ // shared: the built-in handler only reads them, so this is safe in
+ // practice, but a custom TransactionalGatherer that mutates the returned
+ // families in place after Gather returns must not use this option.
+ //
+ // Because the snapshot is shared, a request that arrives while a cycle is
+ // in flight receives that cycle's result even though collection began
+ // before the request; two scrapers joined to one cycle observe the same
+ // timestamps rather than independently gathered data.
+ //
+ // Consider using CoalesceGather together with Timeout. Timeout bounds the
+ // client-facing response time and keeps at most one collection running at
+ // a time, but it does not cancel the underlying Gather: a joined request
+ // that times out still holds a MaxRequestsInFlight slot until the shared
+ // collection completes.
+ //
+ // Panic handling: a panicking Collector is already turned into an error by
+ // the registry, so joiners receive that error like any other. In the rare
+ // case where the wrapped gatherer itself panics, the panicking request's
+ // panic propagates as usual (handled by net/http), while requests that
+ // joined the same cycle receive an error rather than an empty response.
+ //
+ // NOTE: This option is experimental and may change or be removed in a
+ // future release.
+ CoalesceGather bool
// If handling a request takes longer than Timeout, it is responded to
// with 503 ServiceUnavailable and a suitable Message. No timeout is
// applied if Timeout is 0 or negative. Note that with the current
@@ -407,8 +582,9 @@ type HandlerOpts struct {
// described above (and even that only if sending of the body hasn't
// started yet), while the bulk work of gathering all the metrics keeps
// running in the background (with the eventual result to be thrown
- // away). Until the implementation is improved, it is recommended to
- // implement a separate timeout in potentially slow Collectors.
+ // away). When CoalesceGather is enabled, only one such background Gather
+ // can be in flight at a time. It is also recommended to implement a
+ // separate timeout in potentially slow Collectors.
Timeout time.Duration
// If true, the experimental OpenMetrics encoding is added to the
// possible options during content negotiation. Note that Prometheus
@@ -460,7 +636,7 @@ func httpError(rsp http.ResponseWriter, err error) {
// negotiateEncodingWriter reads the Accept-Encoding header from a request and
// selects the right compression based on an allow-list of supported
-// compressions. It returns a writer implementing the compression and an the
+// compressions. It returns a writer implementing the compression and the
// correct value that the caller can set in the response header.
func negotiateEncodingWriter(r *http.Request, rw io.Writer, compressions []string) (_ io.Writer, encodingHeaderValue string, closeWriter func(), _ error) {
if len(compressions) == 0 {
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
index d3482c40ca..0248579742 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
@@ -75,10 +75,10 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
resp, err := next.RoundTrip(r)
if err == nil {
l := labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)
- for label, resolve := range rtOpts.extraLabelsFromCtx {
- l[label] = resolve(resp.Request.Context())
+ for label, resolve := range rtOpts.extraLabelsFromRequest {
+ l[label] = resolve(resp.Request)
}
- addWithExemplar(counter.With(l), 1, rtOpts.getExemplarFn(r.Context()))
+ addWithExemplar(counter.With(l), 1, rtOpts.getExemplarFn(r))
}
return resp, err
}
@@ -119,10 +119,10 @@ func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundT
resp, err := next.RoundTrip(r)
if err == nil {
l := labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)
- for label, resolve := range rtOpts.extraLabelsFromCtx {
- l[label] = resolve(resp.Request.Context())
+ for label, resolve := range rtOpts.extraLabelsFromRequest {
+ l[label] = resolve(resp.Request)
}
- observeWithExemplar(obs.With(l), time.Since(start).Seconds(), rtOpts.getExemplarFn(r.Context()))
+ observeWithExemplar(obs.With(l), time.Since(start).Seconds(), rtOpts.getExemplarFn(r))
}
return resp, err
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
index 9332b0249a..9dec091ac7 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
@@ -28,24 +28,36 @@ import (
// magicString is used for the hacky label test in checkLabels. Remove once fixed.
const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
-// observeWithExemplar is a wrapper for [prometheus.ExemplarAdder.ExemplarObserver],
-// which falls back to [prometheus.Observer.Observe] if no labels are provided.
+// observeWithExemplar records val on obs. If labels is non-nil and obs
+// implements [prometheus.ExemplarObserver], the exemplar is attached via
+// ObserveWithExemplar; otherwise the exemplar is dropped and the value is
+// recorded with a plain [prometheus.Observer.Observe]. This mirrors the
+// safe-cast pattern in [prometheus.Timer.ObserveDurationWithExemplar] and
+// ensures we never panic when callers pass an ObserverVec backed by a
+// summary, which cannot carry exemplars in the Prometheus exposition format.
func observeWithExemplar(obs prometheus.Observer, val float64, labels map[string]string) {
- if labels == nil {
- obs.Observe(val)
- return
+ if labels != nil {
+ if eo, ok := obs.(prometheus.ExemplarObserver); ok {
+ eo.ObserveWithExemplar(val, labels)
+ return
+ }
}
- obs.(prometheus.ExemplarObserver).ObserveWithExemplar(val, labels)
+ obs.Observe(val)
}
-// addWithExemplar is a wrapper for [prometheus.ExemplarAdder.AddWithExemplar],
-// which falls back to [prometheus.Counter.Add] if no labels are provided.
-func addWithExemplar(obs prometheus.Counter, val float64, labels map[string]string) {
- if labels == nil {
- obs.Add(val)
- return
+// addWithExemplar records val on c. If labels is non-nil and c implements
+// [prometheus.ExemplarAdder], the exemplar is attached via AddWithExemplar;
+// otherwise the exemplar is dropped and the value is recorded with a plain
+// [prometheus.Counter.Add]. The safe-cast keeps the helper robust against
+// custom Counter implementations that do not advertise exemplar support.
+func addWithExemplar(c prometheus.Counter, val float64, labels map[string]string) {
+ if labels != nil {
+ if ea, ok := c.(prometheus.ExemplarAdder); ok {
+ ea.AddWithExemplar(val, labels)
+ return
+ }
}
- obs.(prometheus.ExemplarAdder).AddWithExemplar(val, labels)
+ c.Add(val)
}
// InstrumentHandlerInFlight is a middleware that wraps the provided
@@ -97,10 +109,10 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op
next.ServeHTTP(d, r)
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
+ observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r))
}
}
@@ -108,10 +120,10 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op
now := time.Now()
next.ServeHTTP(w, r)
l := labels(code, method, r.Method, 0, hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
+ observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r))
}
}
@@ -147,10 +159,10 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler,
next.ServeHTTP(d, r)
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context()))
+ addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r))
}
}
@@ -158,10 +170,10 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler,
next.ServeHTTP(w, r)
l := labels(code, method, r.Method, 0, hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context()))
+ addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r))
}
}
@@ -200,10 +212,10 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
now := time.Now()
d := newDelegator(w, func(status int) {
l := labels(code, method, r.Method, status, hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
+ observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r))
})
next.ServeHTTP(d, r)
}
@@ -244,10 +256,10 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler,
size := computeApproximateRequestSize(r)
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context()))
+ observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r))
}
}
@@ -256,10 +268,10 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler,
size := computeApproximateRequestSize(r)
l := labels(code, method, r.Method, 0, hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context()))
+ observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r))
}
}
@@ -296,10 +308,10 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler
next.ServeHTTP(d, r)
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
- for label, resolve := range hOpts.extraLabelsFromCtx {
- l[label] = resolve(r.Context())
+ for label, resolve := range hOpts.extraLabelsFromRequest {
+ l[label] = resolve(r)
}
- observeWithExemplar(obs.With(l), float64(d.Written()), hOpts.getExemplarFn(r.Context()))
+ observeWithExemplar(obs.With(l), float64(d.Written()), hOpts.getExemplarFn(r))
})
}
@@ -366,7 +378,7 @@ func checkLabels(c prometheus.Collector) (code, method bool) {
panic("metric partitioned with non-supported labels")
}
}
- return
+ return code, method
}
func isLabelCurried(c prometheus.Collector, label string) bool {
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
index 5d4383aa14..d4c0954f36 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
@@ -15,6 +15,7 @@ package promhttp
import (
"context"
+ "net/http"
"github.com/prometheus/client_golang/prometheus"
)
@@ -24,28 +25,31 @@ type Option interface {
apply(*options)
}
+// LabelValueFromRequest is used to compute the label value from request.
+type LabelValueFromRequest func(request *http.Request) string
+
// LabelValueFromCtx are used to compute the label value from request context.
// Context can be filled with values from request through middleware.
type LabelValueFromCtx func(ctx context.Context) string
// options store options for both a handler or round tripper.
type options struct {
- extraMethods []string
- getExemplarFn func(requestCtx context.Context) prometheus.Labels
- extraLabelsFromCtx map[string]LabelValueFromCtx
+ extraMethods []string
+ getExemplarFn func(req *http.Request) prometheus.Labels
+ extraLabelsFromRequest map[string]LabelValueFromRequest
}
func defaultOptions() *options {
return &options{
- getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil },
- extraLabelsFromCtx: map[string]LabelValueFromCtx{},
+ getExemplarFn: func(req *http.Request) prometheus.Labels { return nil },
+ extraLabelsFromRequest: map[string]LabelValueFromRequest{},
}
}
func (o *options) emptyDynamicLabels() prometheus.Labels {
labels := prometheus.Labels{}
- for label := range o.extraLabelsFromCtx {
+ for label := range o.extraLabelsFromRequest {
labels[label] = ""
}
@@ -66,19 +70,39 @@ func WithExtraMethods(methods ...string) Option {
})
}
-// WithExemplarFromContext allows to inject function that will get exemplar from context that will be put to counter and histogram metrics.
+// WithExemplarFromRequest allows you to inject a function that will get exemplar from request that will be put to counter and histogram metrics.
// If the function returns nil labels or the metric does not support exemplars, no exemplar will be added (noop), but
// metric will continue to observe/increment.
-func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option {
+func WithExemplarFromRequest(getExemplarFn func(req *http.Request) prometheus.Labels) Option {
return optionApplyFunc(func(o *options) {
o.getExemplarFn = getExemplarFn
})
}
+// WithExemplarFromContext allows you to inject a function that will get exemplar from context that will be put to counter and histogram metrics.
+// If the function returns nil labels or the metric does not support exemplars, no exemplar will be added (noop), but
+// metric will continue to observe/increment.
+func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option {
+ return optionApplyFunc(func(o *options) {
+ o.getExemplarFn = func(req *http.Request) prometheus.Labels {
+ return getExemplarFn(req.Context())
+ }
+ })
+}
+
+// WithLabelFromRequest registers a label for dynamic resolution with access to the request.
+func WithLabelFromRequest(name string, valueFn LabelValueFromRequest) Option {
+ return optionApplyFunc(func(o *options) {
+ o.extraLabelsFromRequest[name] = valueFn
+ })
+}
+
// WithLabelFromCtx registers a label for dynamic resolution with access to context.
// See the example for ExampleInstrumentHandlerWithLabelResolver for example usage
func WithLabelFromCtx(name string, valueFn LabelValueFromCtx) Option {
return optionApplyFunc(func(o *options) {
- o.extraLabelsFromCtx[name] = valueFn
+ o.extraLabelsFromRequest[name] = func(req *http.Request) string {
+ return valueFn(req.Context())
+ }
})
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go
index c6fd2f58b7..ed0681c8b4 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go
@@ -214,6 +214,19 @@ func (err AlreadyRegisteredError) Error() string {
// by a Gatherer to report multiple errors during MetricFamily gathering.
type MultiError []error
+// SafeMultiError is a thread-safe wrapper around MultiError using a mutex.
+type SafeMultiError struct {
+ mu sync.Mutex
+ errs MultiError
+}
+
+// Appends the provided error to the contained MultiError in a thread-safe way.
+func (s *SafeMultiError) Append(err error) {
+ s.mu.Lock()
+ s.errs.Append(err)
+ s.mu.Unlock()
+}
+
// Error formats the contained errors as a bullet point list, preceded by the
// total number of errors. Note that this results in a multi-line string.
func (errs MultiError) Error() string {
@@ -408,6 +421,16 @@ func (r *Registry) MustRegister(cs ...Collector) {
}
}
+// MustGather implements Gatherer.
+// Wraps around Gather and panics if Gather fails for any reason.
+func (r *Registry) MustGather() []*dto.MetricFamily {
+ mfs, err := r.Gather()
+ if err != nil {
+ panic(err)
+ }
+ return mfs
+}
+
// Gather implements Gatherer.
func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
r.mtx.RLock()
@@ -423,7 +446,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
uncheckedMetricChan = make(chan Metric, capMetricChan)
metricHashes = map[uint64]struct{}{}
wg sync.WaitGroup
- errs MultiError // The collected errors to return in the end.
+ safeErrs = &SafeMultiError{} // To collect errors in a threadsafe way
registeredDescIDs map[uint64]struct{} // Only used for pedantic checks
)
@@ -453,9 +476,9 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
for {
select {
case collector := <-checkedCollectors:
- collector.Collect(checkedMetricChan)
+ safeErrs.Append((safeCollect(collector, checkedMetricChan)))
case collector := <-uncheckedCollectors:
- collector.Collect(uncheckedMetricChan)
+ safeErrs.Append(safeCollect(collector, uncheckedMetricChan))
default:
return
}
@@ -499,7 +522,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
cmc = nil
break
}
- errs.Append(processMetric(
+ safeErrs.Append(processMetric(
metric, metricFamiliesByName,
metricHashes,
registeredDescIDs,
@@ -509,7 +532,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
umc = nil
break
}
- errs.Append(processMetric(
+ safeErrs.Append(processMetric(
metric, metricFamiliesByName,
metricHashes,
nil,
@@ -526,7 +549,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
cmc = nil
break
}
- errs.Append(processMetric(
+ safeErrs.Append(processMetric(
metric, metricFamiliesByName,
metricHashes,
registeredDescIDs,
@@ -536,7 +559,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
umc = nil
break
}
- errs.Append(processMetric(
+ safeErrs.Append(processMetric(
metric, metricFamiliesByName,
metricHashes,
nil,
@@ -556,7 +579,8 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
break
}
}
- return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap()
+
+ return internal.NormalizeMetricFamilies(metricFamiliesByName), safeErrs.errs.MaybeUnwrap()
}
// Describe implements Collector.
@@ -571,6 +595,24 @@ func (r *Registry) Describe(ch chan<- *Desc) {
}
}
+// Helper wrapper around Collector.Collect.
+// It tries to collect from the channel, recovers on panic and
+// if it has recovered from a panic, then it sends an InvalidMetric into
+// the channel with an InvalidDesc, and an error that includes a stack trace.
+func safeCollect(c Collector, ch chan<- Metric) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ buf := make([]byte, 64<<10) // 64 KB
+ n := runtime.Stack(buf, false)
+ err = fmt.Errorf("prometheus collector panic recovered: type=%T: error=%v\nstack trace=%s", c, r, buf[:n])
+ ch <- NewInvalidMetric(NewInvalidDesc(err), err)
+ }
+ }()
+ c.Collect(ch)
+
+ return err
+}
+
// Collect implements Collector.
func (r *Registry) Collect(ch chan<- Metric) {
r.mtx.RLock()
@@ -599,10 +641,12 @@ func WriteToTextfile(filename string, g Gatherer) error {
mfs, err := g.Gather()
if err != nil {
+ tmp.Close()
return err
}
for _, mf := range mfs {
if _, err := expfmt.MetricFamilyToText(tmp, mf); err != nil {
+ tmp.Close()
return err
}
}
@@ -685,6 +729,9 @@ func processMetric(
metricFamily = &dto.MetricFamily{}
metricFamily.Name = proto.String(desc.fqName)
metricFamily.Help = proto.String(desc.help)
+ if desc.unit != "" {
+ metricFamily.Unit = proto.String(desc.unit)
+ }
// TODO(beorn7): Simplify switch once Desc has type.
switch {
case dtoMetric.Gauge != nil:
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go
index ac5203c6fa..c12b8d13d4 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go
@@ -101,6 +101,9 @@ type SummaryOpts struct {
// string.
Help string
+ // Unit provides the unit of this Summary.
+ Unit string
+
// ConstLabels are used to attach fixed labels to this metric. Metrics
// with the same fully-qualified name must have the same label names in
// their ConstLabels.
@@ -181,11 +184,12 @@ type SummaryVecOpts struct {
// NewSummary creates a new Summary based on the provided SummaryOpts.
func NewSummary(opts SummaryOpts) Summary {
return newSummary(
- NewDesc(
+ V2.NewDesc(
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
opts.Help,
- nil,
+ UnconstrainedLabels(nil),
opts.ConstLabels,
+ WithUnit(opts.Unit),
),
opts,
)
@@ -578,6 +582,7 @@ func (v2) NewSummaryVec(opts SummaryVecOpts) *SummaryVec {
opts.Help,
opts.VariableLabels,
opts.ConstLabels,
+ WithUnit(opts.Unit),
)
return &SummaryVec{
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go
index 52344fef53..c1318ffb51 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/timer.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go
@@ -37,10 +37,10 @@ type Timer struct {
// or
//
// func TimeMeWithExemplar() {
-// timer := NewTimer(myHistogram)
-// defer timer.ObserveDurationWithExemplar(exemplar)
-// // Do actual work.
-// }
+// timer := NewTimer(myHistogram)
+// defer timer.ObserveDurationWithExemplar(exemplar)
+// // Do actual work.
+// }
func NewTimer(o Observer) *Timer {
return &Timer{
begin: time.Now(),
@@ -66,7 +66,7 @@ func (t *Timer) ObserveDuration() time.Duration {
// ObserveDurationWithExemplar is like ObserveDuration, but it will also
// observe exemplar with the duration unless exemplar is nil or provided Observer can't
-// be casted to ExemplarObserver.
+// be cast to ExemplarObserver.
func (t *Timer) ObserveDurationWithExemplar(exemplar Labels) time.Duration {
d := time.Since(t.begin)
eo, ok := t.observer.(ExemplarObserver)
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vec.go b/vendor/github.com/prometheus/client_golang/prometheus/vec.go
index 487b466563..121d2a9639 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/vec.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/vec.go
@@ -193,9 +193,11 @@ func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) {
//
// Keeping the Metric for later use is possible (and should be considered if
// performance is critical), but keep in mind that Reset, DeleteLabelValues and
-// Delete can be used to delete the Metric from the MetricVec. In that case, the
-// Metric will still exist, but it will not be exported anymore, even if a
-// Metric with the same label values is created later.
+// Delete can be used to delete the Metric from the MetricVec. In that case, if
+// you have previously kept a reference to that Metric, the Metric object still
+// exists and can be used, but it will not be exported anymore. If a Metric with
+// the same label values is created later, updates to the old Metric reference
+// will not be exported.
//
// An error is returned if the number of label values is not the same as the
// number of variable labels in Desc (minus any curried labels).
@@ -657,7 +659,7 @@ func inlineLabelValues(lvs []string, curry []curriedLabelValue) []string {
}
var labelsPool = &sync.Pool{
- New: func() interface{} {
+ New: func() any {
return make(Labels)
},
}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go
index 2ed1285068..697f55558b 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go
@@ -230,6 +230,7 @@ func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc {
return &Desc{
fqName: desc.fqName,
help: desc.help,
+ unit: desc.unit,
variableLabels: desc.variableLabels,
constLabelPairs: desc.constLabelPairs,
err: fmt.Errorf("attempted wrapping with already existing label name %q", ln),
@@ -238,8 +239,8 @@ func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc {
constLabels[ln] = lv
}
// NewDesc will do remaining validations.
- newDesc := V2.NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels)
- // Propagate errors if there was any. This will override any errer
+ newDesc := V2.NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels, WithUnit(desc.unit))
+ // Propagate errors if there was any. This will override any error
// created by NewDesc above, i.e. earlier errors get precedence.
if desc.err != nil {
newDesc.err = desc.err
diff --git a/vendor/github.com/prometheus/common/expfmt/decode.go b/vendor/github.com/prometheus/common/expfmt/decode.go
index 7b762370e2..8f8dc65d38 100644
--- a/vendor/github.com/prometheus/common/expfmt/decode.go
+++ b/vendor/github.com/prometheus/common/expfmt/decode.go
@@ -220,7 +220,7 @@ func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error)
return extractSummary(o, f), nil
case dto.MetricType_UNTYPED:
return extractUntyped(o, f), nil
- case dto.MetricType_HISTOGRAM:
+ case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
return extractHistogram(o, f), nil
}
return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType())
@@ -403,9 +403,13 @@ func extractHistogram(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
infSeen = true
}
+ v := q.GetCumulativeCountFloat()
+ if v <= 0 {
+ v = float64(q.GetCumulativeCount())
+ }
samples = append(samples, &model.Sample{
Metric: model.Metric(lset),
- Value: model.SampleValue(q.GetCumulativeCount()),
+ Value: model.SampleValue(v),
Timestamp: timestamp,
})
}
@@ -428,9 +432,13 @@ func extractHistogram(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
}
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
+ v := m.Histogram.GetSampleCountFloat()
+ if v <= 0 {
+ v = float64(m.Histogram.GetSampleCount())
+ }
count := &model.Sample{
Metric: model.Metric(lset),
- Value: model.SampleValue(m.Histogram.GetSampleCount()),
+ Value: model.SampleValue(v),
Timestamp: timestamp,
}
samples = append(samples, count)
diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go
index c34c7de432..10bf35708c 100644
--- a/vendor/github.com/prometheus/common/expfmt/expfmt.go
+++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go
@@ -45,6 +45,7 @@ const (
// The Content-Type values for the different wire protocols. Do not do direct
// comparisons to these constants, instead use the comparison functions.
+ //
// Deprecated: Use expfmt.NewFormat(expfmt.TypeUnknown) instead.
FmtUnknown Format = ``
// Deprecated: Use expfmt.NewFormat(expfmt.TypeTextPlain) instead.
@@ -121,7 +122,7 @@ func NewOpenMetricsFormat(version string) (Format, error) {
// removed.
func (f Format) WithEscapingScheme(s model.EscapingScheme) Format {
var terms []string
- for _, p := range strings.Split(string(f), ";") {
+ for p := range strings.SplitSeq(string(f), ";") {
toks := strings.Split(p, "=")
if len(toks) != 2 {
trimmed := strings.TrimSpace(p)
@@ -193,7 +194,7 @@ func (f Format) FormatType() FormatType {
// "escaping" term exists, that will be used. Otherwise, the global default will
// be returned.
func (f Format) ToEscapingScheme() model.EscapingScheme {
- for _, p := range strings.Split(string(f), ";") {
+ for p := range strings.SplitSeq(string(f), ";") {
toks := strings.Split(p, "=")
if len(toks) != 2 {
continue
diff --git a/vendor/github.com/prometheus/common/expfmt/fuzz.go b/vendor/github.com/prometheus/common/expfmt/fuzz.go
index 0290f6abc4..872c0c15b4 100644
--- a/vendor/github.com/prometheus/common/expfmt/fuzz.go
+++ b/vendor/github.com/prometheus/common/expfmt/fuzz.go
@@ -13,7 +13,6 @@
// Build only when actually fuzzing
//go:build gofuzz
-// +build gofuzz
package expfmt
diff --git a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
index 8dbf6d04ed..0480e7af5b 100644
--- a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
+++ b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
@@ -30,7 +30,6 @@ import (
type encoderOption struct {
withCreatedLines bool
- withUnit bool
}
type EncoderOption func(*encoderOption)
@@ -51,17 +50,6 @@ func WithCreatedLines() EncoderOption {
}
}
-// WithUnit is an EncoderOption enabling a set unit to be written to the output
-// and to be added to the metric name, if it's not there already, as a suffix.
-// Without opting in this way, the unit will not be added to the metric name and,
-// on top of that, the unit will not be passed onto the output, even if it
-// were declared in the *dto.MetricFamily struct, i.e. even if in.Unit !=nil.
-func WithUnit() EncoderOption {
- return func(t *encoderOption) {
- t.withUnit = true
- }
-}
-
// MetricFamilyToOpenMetrics converts a MetricFamily proto message into the
// OpenMetrics text format and writes the resulting lines to 'out'. It returns
// the number of bytes written and any error encountered. The output will have
@@ -99,15 +87,6 @@ func WithUnit() EncoderOption {
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
// output.
//
-// - According to the OM specs, the `# UNIT` line is optional, but if populated,
-// the unit has to be present in the metric name as its suffix:
-// (see https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#unit).
-// However, in order to accommodate any potential scenario where such a change in the
-// metric name is not desirable, the users are here given the choice of either explicitly
-// opt in, in case they wish for the unit to be included in the output AND in the metric name
-// as a suffix (see the description of the WithUnit function above),
-// or not to opt in, in case they don't want for any of that to happen.
-//
// - No support for the following (optional) features: info type,
// stateset type, gaugehistogram type.
//
@@ -151,47 +130,44 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
if metricType == dto.MetricType_COUNTER && strings.HasSuffix(compliantName, "_total") {
compliantName = name[:len(name)-6]
}
- if toOM.withUnit && in.Unit != nil && !strings.HasSuffix(compliantName, "_"+*in.Unit) {
- compliantName = compliantName + "_" + *in.Unit
- }
// Comments, first HELP, then TYPE.
if in.Help != nil {
n, err = w.WriteString("# HELP ")
written += n
if err != nil {
- return
+ return written, err
}
n, err = writeName(w, compliantName)
written += n
if err != nil {
- return
+ return written, err
}
err = w.WriteByte(' ')
written++
if err != nil {
- return
+ return written, err
}
n, err = writeEscapedString(w, *in.Help, true)
written += n
if err != nil {
- return
+ return written, err
}
err = w.WriteByte('\n')
written++
if err != nil {
- return
+ return written, err
}
}
n, err = w.WriteString("# TYPE ")
written += n
if err != nil {
- return
+ return written, err
}
n, err = writeName(w, compliantName)
written += n
if err != nil {
- return
+ return written, err
}
switch metricType {
case dto.MetricType_COUNTER:
@@ -208,39 +184,41 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
n, err = w.WriteString(" unknown\n")
case dto.MetricType_HISTOGRAM:
n, err = w.WriteString(" histogram\n")
+ case dto.MetricType_GAUGE_HISTOGRAM:
+ n, err = w.WriteString(" gaugehistogram\n")
default:
return written, fmt.Errorf("unknown metric type %s", metricType.String())
}
written += n
if err != nil {
- return
+ return written, err
}
- if toOM.withUnit && in.Unit != nil {
+ if in.Unit != nil {
n, err = w.WriteString("# UNIT ")
written += n
if err != nil {
- return
+ return written, err
}
n, err = writeName(w, compliantName)
written += n
if err != nil {
- return
+ return written, err
}
err = w.WriteByte(' ')
written++
if err != nil {
- return
+ return written, err
}
n, err = writeEscapedString(w, *in.Unit, true)
written += n
if err != nil {
- return
+ return written, err
}
err = w.WriteByte('\n')
written++
if err != nil {
- return
+ return written, err
}
}
@@ -304,7 +282,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
)
written += n
if err != nil {
- return
+ return written, err
}
}
n, err = writeOpenMetricsSample(
@@ -314,7 +292,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
)
written += n
if err != nil {
- return
+ return written, err
}
n, err = writeOpenMetricsSample(
w, compliantName, "_count", metric, "", 0,
@@ -325,7 +303,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "", metric, "", 0, metric.Summary.GetCreatedTimestamp())
n += createdTsBytesWritten
}
- case dto.MetricType_HISTOGRAM:
+ case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
if metric.Histogram == nil {
return written, fmt.Errorf(
"expected histogram in metric %s %s", compliantName, metric,
@@ -333,6 +311,12 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
}
infSeen := false
for _, b := range metric.Histogram.Bucket {
+ if b.GetCumulativeCountFloat() > 0 {
+ return written, fmt.Errorf(
+ "OpenMetrics v1.0 does not support float histogram %s %s",
+ compliantName, metric,
+ )
+ }
n, err = writeOpenMetricsSample(
w, compliantName, "_bucket", metric,
model.BucketLabel, b.GetUpperBound(),
@@ -341,7 +325,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
)
written += n
if err != nil {
- return
+ return written, err
}
if math.IsInf(b.GetUpperBound(), +1) {
infSeen = true
@@ -354,9 +338,12 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
0, metric.Histogram.GetSampleCount(), true,
nil,
)
+ // We do not check for a float sample count here
+ // because we will check for it below (and error
+ // out if needed).
written += n
if err != nil {
- return
+ return written, err
}
}
n, err = writeOpenMetricsSample(
@@ -366,7 +353,13 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
)
written += n
if err != nil {
- return
+ return written, err
+ }
+ if metric.Histogram.GetSampleCountFloat() > 0 {
+ return written, fmt.Errorf(
+ "OpenMetrics v1.0 does not support float histogram %s %s",
+ compliantName, metric,
+ )
}
n, err = writeOpenMetricsSample(
w, compliantName, "_count", metric, "", 0,
@@ -384,10 +377,10 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...E
}
written += n
if err != nil {
- return
+ return written, err
}
}
- return
+ return written, err
}
// FinalizeOpenMetrics writes the final `# EOF\n` line required by OpenMetrics.
diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go
index c4e9c1bbc3..f4074ae9a3 100644
--- a/vendor/github.com/prometheus/common/expfmt/text_create.go
+++ b/vendor/github.com/prometheus/common/expfmt/text_create.go
@@ -42,12 +42,12 @@ const (
var (
bufPool = sync.Pool{
- New: func() interface{} {
+ New: func() any {
return bufio.NewWriter(io.Discard)
},
}
numBufPool = sync.Pool{
- New: func() interface{} {
+ New: func() any {
b := make([]byte, 0, initialNumBufSize)
return &b
},
@@ -108,38 +108,38 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
n, err = w.WriteString("# HELP ")
written += n
if err != nil {
- return
+ return written, err
}
n, err = writeName(w, name)
written += n
if err != nil {
- return
+ return written, err
}
err = w.WriteByte(' ')
written++
if err != nil {
- return
+ return written, err
}
n, err = writeEscapedString(w, *in.Help, false)
written += n
if err != nil {
- return
+ return written, err
}
err = w.WriteByte('\n')
written++
if err != nil {
- return
+ return written, err
}
}
n, err = w.WriteString("# TYPE ")
written += n
if err != nil {
- return
+ return written, err
}
n, err = writeName(w, name)
written += n
if err != nil {
- return
+ return written, err
}
metricType := in.GetType()
switch metricType {
@@ -151,14 +151,17 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
n, err = w.WriteString(" summary\n")
case dto.MetricType_UNTYPED:
n, err = w.WriteString(" untyped\n")
- case dto.MetricType_HISTOGRAM:
+ case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
+ // The classic Prometheus text format has no notion of a gauge
+ // histogram. We render a gauge histogram in the same way as a
+ // regular histogram.
n, err = w.WriteString(" histogram\n")
default:
return written, fmt.Errorf("unknown metric type %s", metricType.String())
}
written += n
if err != nil {
- return
+ return written, err
}
// Finally the samples, one line for each.
@@ -208,7 +211,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
)
written += n
if err != nil {
- return
+ return written, err
}
}
n, err = writeSample(
@@ -217,13 +220,13 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
)
written += n
if err != nil {
- return
+ return written, err
}
n, err = writeSample(
w, name, "_count", metric, "", 0,
float64(metric.Summary.GetSampleCount()),
)
- case dto.MetricType_HISTOGRAM:
+ case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
if metric.Histogram == nil {
return written, fmt.Errorf(
"expected histogram in metric %s %s", name, metric,
@@ -231,28 +234,36 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
}
infSeen := false
for _, b := range metric.Histogram.Bucket {
+ v := b.GetCumulativeCountFloat()
+ if v == 0 {
+ v = float64(b.GetCumulativeCount())
+ }
n, err = writeSample(
w, name, "_bucket", metric,
model.BucketLabel, b.GetUpperBound(),
- float64(b.GetCumulativeCount()),
+ v,
)
written += n
if err != nil {
- return
+ return written, err
}
if math.IsInf(b.GetUpperBound(), +1) {
infSeen = true
}
}
if !infSeen {
+ v := metric.Histogram.GetSampleCountFloat()
+ if v == 0 {
+ v = float64(metric.Histogram.GetSampleCount())
+ }
n, err = writeSample(
w, name, "_bucket", metric,
model.BucketLabel, math.Inf(+1),
- float64(metric.Histogram.GetSampleCount()),
+ v,
)
written += n
if err != nil {
- return
+ return written, err
}
}
n, err = writeSample(
@@ -261,12 +272,13 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
)
written += n
if err != nil {
- return
+ return written, err
}
- n, err = writeSample(
- w, name, "_count", metric, "", 0,
- float64(metric.Histogram.GetSampleCount()),
- )
+ v := metric.Histogram.GetSampleCountFloat()
+ if v == 0 {
+ v = float64(metric.Histogram.GetSampleCount())
+ }
+ n, err = writeSample(w, name, "_count", metric, "", 0, v)
default:
return written, fmt.Errorf(
"unexpected type in metric %s %s", name, metric,
@@ -274,10 +286,10 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
}
written += n
if err != nil {
- return
+ return written, err
}
}
- return
+ return written, err
}
// writeSample writes a single sample in text format to w, given the metric
diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go
index 8f2edde324..4ce1f40b81 100644
--- a/vendor/github.com/prometheus/common/expfmt/text_parse.go
+++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go
@@ -48,8 +48,10 @@ func (e ParseError) Error() string {
return fmt.Sprintf("text format parsing error in line %d: %s", e.Line, e.Msg)
}
-// TextParser is used to parse the simple and flat text-based exchange format. Its
-// zero value is ready to use.
+// TextParser is used to parse the simple and flat text-based exchange format.
+//
+// TextParser instances must be created with NewTextParser, the zero value of
+// TextParser is invalid.
type TextParser struct {
metricFamiliesByName map[string]*dto.MetricFamily
buf *bufio.Reader // Where the parsed input is read through.
@@ -129,9 +131,44 @@ func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricF
if p.err != nil && errors.Is(p.err, io.EOF) {
p.parseError("unexpected end of input stream")
}
+ for _, histogramMetric := range p.histograms {
+ normalizeHistogram(histogramMetric.GetHistogram())
+ }
return p.metricFamiliesByName, p.err
}
+// normalizeHistogram makes sure that all the buckets and the count in each
+// histogram is either completely float or completely integer.
+func normalizeHistogram(histogram *dto.Histogram) {
+ if histogram == nil {
+ return
+ }
+ anyFloats := false
+ if histogram.GetSampleCountFloat() != 0 {
+ anyFloats = true
+ } else {
+ for _, b := range histogram.GetBucket() {
+ if b.GetCumulativeCountFloat() != 0 {
+ anyFloats = true
+ break
+ }
+ }
+ }
+ if !anyFloats {
+ return
+ }
+ if histogram.GetSampleCountFloat() == 0 {
+ histogram.SampleCountFloat = proto.Float64(float64(histogram.GetSampleCount()))
+ histogram.SampleCount = nil
+ }
+ for _, b := range histogram.GetBucket() {
+ if b.GetCumulativeCountFloat() == 0 {
+ b.CumulativeCountFloat = proto.Float64(float64(b.GetCumulativeCount()))
+ b.CumulativeCount = nil
+ }
+ }
+}
+
func (p *TextParser) reset(in io.Reader) {
p.metricFamiliesByName = map[string]*dto.MetricFamily{}
p.currentLabelPairs = nil
@@ -281,7 +318,9 @@ func (p *TextParser) readingLabels() stateFn {
// Summaries/histograms are special. We have to reset the
// currentLabels map, currentQuantile and currentBucket before starting to
// read labels.
- if p.currentMF.GetType() == dto.MetricType_SUMMARY || p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
+ if p.currentMF.GetType() == dto.MetricType_SUMMARY ||
+ p.currentMF.GetType() == dto.MetricType_HISTOGRAM ||
+ p.currentMF.GetType() == dto.MetricType_GAUGE_HISTOGRAM {
p.currentLabels = map[string]string{}
p.currentLabels[string(model.MetricNameLabel)] = p.currentMF.GetName()
p.currentQuantile = math.NaN()
@@ -300,6 +339,16 @@ func (p *TextParser) startLabelName() stateFn {
return nil // Unexpected end of input.
}
if p.currentByte == '}' {
+ if p.currentMF == nil {
+ // The closing brace was reached before any metric name was read,
+ // e.g. for the input "{}". There is no metric to attach labels to,
+ // so this is a malformed exposition. This mirrors the guard in
+ // startLabelValue. currentMF (not currentMetric) is checked because
+ // reset only clears currentMF between parses.
+ p.parseError("invalid metric name")
+ p.currentLabelPairs = nil
+ return nil
+ }
p.currentMetric.Label = append(p.currentMetric.Label, p.currentLabelPairs...)
p.currentLabelPairs = nil
if p.skipBlankTab(); p.err != nil {
@@ -374,7 +423,9 @@ func (p *TextParser) startLabelName() stateFn {
// Special summary/histogram treatment. Don't add 'quantile' and 'le'
// labels to 'real' labels.
if (p.currentMF.GetType() != dto.MetricType_SUMMARY || p.currentLabelPair.GetName() != model.QuantileLabel) &&
- (p.currentMF.GetType() != dto.MetricType_HISTOGRAM || p.currentLabelPair.GetName() != model.BucketLabel) {
+ ((p.currentMF.GetType() != dto.MetricType_HISTOGRAM &&
+ p.currentMF.GetType() != dto.MetricType_GAUGE_HISTOGRAM) ||
+ p.currentLabelPair.GetName() != model.BucketLabel) {
p.currentLabelPairs = append(p.currentLabelPairs, p.currentLabelPair)
}
// Check for duplicate label names.
@@ -425,7 +476,7 @@ func (p *TextParser) startLabelValue() stateFn {
}
}
// Similar special treatment of histograms.
- if p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
+ if p.currentMF.GetType() == dto.MetricType_HISTOGRAM || p.currentMF.GetType() == dto.MetricType_GAUGE_HISTOGRAM {
if p.currentLabelPair.GetName() == model.BucketLabel {
if p.currentBucket, p.err = parseFloat(p.currentLabelPair.GetValue()); p.err != nil {
// Create a more helpful error message.
@@ -476,7 +527,7 @@ func (p *TextParser) readingValue() stateFn {
p.summaries[signature] = p.currentMetric
p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric)
}
- case dto.MetricType_HISTOGRAM:
+ case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
signature := model.LabelsToSignature(p.currentLabels)
if histogram := p.histograms[signature]; histogram != nil {
p.currentMetric = histogram
@@ -522,24 +573,38 @@ func (p *TextParser) readingValue() stateFn {
},
)
}
- case dto.MetricType_HISTOGRAM:
+ case dto.MetricType_HISTOGRAM, dto.MetricType_GAUGE_HISTOGRAM:
// *sigh*
if p.currentMetric.Histogram == nil {
p.currentMetric.Histogram = &dto.Histogram{}
}
switch {
case p.currentIsHistogramCount:
- p.currentMetric.Histogram.SampleCount = proto.Uint64(uint64(value))
+ if uintValue := uint64(value); value == float64(uintValue) {
+ p.currentMetric.Histogram.SampleCount = proto.Uint64(uintValue)
+ } else {
+ if value < 0 {
+ p.parseError(fmt.Sprintf("negative count for histogram %q", p.currentMF.GetName()))
+ return nil
+ }
+ p.currentMetric.Histogram.SampleCountFloat = proto.Float64(value)
+ }
case p.currentIsHistogramSum:
p.currentMetric.Histogram.SampleSum = proto.Float64(value)
case !math.IsNaN(p.currentBucket):
- p.currentMetric.Histogram.Bucket = append(
- p.currentMetric.Histogram.Bucket,
- &dto.Bucket{
- UpperBound: proto.Float64(p.currentBucket),
- CumulativeCount: proto.Uint64(uint64(value)),
- },
- )
+ b := &dto.Bucket{
+ UpperBound: proto.Float64(p.currentBucket),
+ }
+ if uintValue := uint64(value); value == float64(uintValue) {
+ b.CumulativeCount = proto.Uint64(uintValue)
+ } else {
+ if value < 0 {
+ p.parseError(fmt.Sprintf("negative bucket population for histogram %q", p.currentMF.GetName()))
+ return nil
+ }
+ b.CumulativeCountFloat = proto.Float64(value)
+ }
+ p.currentMetric.Histogram.Bucket = append(p.currentMetric.Histogram.Bucket, b)
}
default:
p.err = fmt.Errorf("unexpected type for metric name %q", p.currentMF.GetName())
@@ -602,10 +667,18 @@ func (p *TextParser) readingType() stateFn {
if p.readTokenUntilNewline(false); p.err != nil {
return nil // Unexpected end of input.
}
- metricType, ok := dto.MetricType_value[strings.ToUpper(p.currentToken.String())]
+ typ := strings.ToUpper(p.currentToken.String()) // Tolerate any combination of upper and lower case.
+ metricType, ok := dto.MetricType_value[typ] // Tolerate "gauge_histogram" (not originally part of the text format).
if !ok {
- p.parseError(fmt.Sprintf("unknown metric type %q", p.currentToken.String()))
- return nil
+ // We also want to tolerate "gaugehistogram" to mark a gauge
+ // histogram, because that string is used in OpenMetrics. Note,
+ // however, that gauge histograms do not officially exist in the
+ // classic text format.
+ if typ != "GAUGEHISTOGRAM" {
+ p.parseError(fmt.Sprintf("unknown metric type %q", p.currentToken.String()))
+ return nil
+ }
+ metricType = int32(dto.MetricType_GAUGE_HISTOGRAM)
}
p.currentMF.Type = dto.MetricType(metricType).Enum()
return p.startOfLine
@@ -855,7 +928,8 @@ func (p *TextParser) setOrCreateCurrentMF() {
}
histogramName := histogramMetricName(name)
if p.currentMF = p.metricFamiliesByName[histogramName]; p.currentMF != nil {
- if p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
+ if p.currentMF.GetType() == dto.MetricType_HISTOGRAM ||
+ p.currentMF.GetType() == dto.MetricType_GAUGE_HISTOGRAM {
if isCount(name) {
p.currentIsHistogramCount = true
}
diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go
index dfeb34be5f..29688a13c8 100644
--- a/vendor/github.com/prometheus/common/model/labels.go
+++ b/vendor/github.com/prometheus/common/model/labels.go
@@ -124,7 +124,7 @@ func (ln LabelName) IsValidLegacy() bool {
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
-func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error {
+func (ln *LabelName) UnmarshalYAML(unmarshal func(any) error) error {
var s string
if err := unmarshal(&s); err != nil {
return err
diff --git a/vendor/github.com/prometheus/common/model/labelset.go b/vendor/github.com/prometheus/common/model/labelset.go
index 9de47b2568..6010b26a88 100644
--- a/vendor/github.com/prometheus/common/model/labelset.go
+++ b/vendor/github.com/prometheus/common/model/labelset.go
@@ -16,6 +16,7 @@ package model
import (
"encoding/json"
"fmt"
+ "maps"
"sort"
)
@@ -107,9 +108,7 @@ func (ls LabelSet) Before(o LabelSet) bool {
// Clone returns a copy of the label set.
func (ls LabelSet) Clone() LabelSet {
lsn := make(LabelSet, len(ls))
- for ln, lv := range ls {
- lsn[ln] = lv
- }
+ maps.Copy(lsn, ls)
return lsn
}
@@ -117,13 +116,9 @@ func (ls LabelSet) Clone() LabelSet {
func (ls LabelSet) Merge(other LabelSet) LabelSet {
result := make(LabelSet, len(ls))
- for k, v := range ls {
- result[k] = v
- }
+ maps.Copy(result, ls)
- for k, v := range other {
- result[k] = v
- }
+ maps.Copy(result, other)
return result
}
diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go
index 3feebf328a..2fe461511d 100644
--- a/vendor/github.com/prometheus/common/model/metric.go
+++ b/vendor/github.com/prometheus/common/model/metric.go
@@ -17,6 +17,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "maps"
"regexp"
"sort"
"strconv"
@@ -24,7 +25,6 @@ import (
"unicode/utf8"
dto "github.com/prometheus/client_model/go"
- "go.yaml.in/yaml/v2"
"google.golang.org/protobuf/proto"
)
@@ -78,14 +78,6 @@ const (
UTF8Validation
)
-var _ interface {
- yaml.Marshaler
- yaml.Unmarshaler
- json.Marshaler
- json.Unmarshaler
- fmt.Stringer
-} = new(ValidationScheme)
-
// String returns the string representation of s.
func (s ValidationScheme) String() string {
switch s {
@@ -267,9 +259,7 @@ func (m Metric) Before(o Metric) bool {
// Clone returns a copy of the Metric.
func (m Metric) Clone() Metric {
clone := make(Metric, len(m))
- for k, v := range m {
- clone[k] = v
- }
+ maps.Copy(clone, m)
return clone
}
diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go
index 1730b0fdc1..0854753f4a 100644
--- a/vendor/github.com/prometheus/common/model/time.go
+++ b/vendor/github.com/prometheus/common/model/time.go
@@ -123,44 +123,38 @@ func (t Time) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
func (t *Time) UnmarshalJSON(b []byte) error {
- p := strings.Split(string(b), ".")
- switch len(p) {
- case 1:
- v, err := strconv.ParseInt(p[0], 10, 64)
+ base, frac, found := strings.Cut(string(b), ".")
+ if !found {
+ v, err := strconv.ParseInt(base, 10, 64)
if err != nil {
return err
}
*t = Time(v * second)
-
- case 2:
- v, err := strconv.ParseInt(p[0], 10, 64)
+ } else {
+ v, err := strconv.ParseInt(base, 10, 64)
if err != nil {
return err
}
- v *= second
- prec := dotPrecision - len(p[1])
+ prec := dotPrecision - len(frac)
if prec < 0 {
- p[1] = p[1][:dotPrecision]
- } else if prec > 0 {
- p[1] += strings.Repeat("0", prec)
+ frac = frac[:dotPrecision]
}
-
- va, err := strconv.ParseInt(p[1], 10, 32)
+ va, err := strconv.ParseInt(frac, 10, 32)
if err != nil {
return err
}
-
- // If the value was something like -0.1 the negative is lost in the
- // parsing because of the leading zero, this ensures that we capture it.
- if len(p[0]) > 0 && p[0][0] == '-' && v+va > 0 {
- *t = Time(v+va) * -1
- } else {
- *t = Time(v + va)
+ switch prec {
+ case 1:
+ va *= 10
+ case 2:
+ va *= 100
}
- default:
- return fmt.Errorf("invalid time %q", string(b))
+ if len(base) > 0 && base[0] == '-' {
+ va = -va
+ }
+ *t = Time(v*second + va)
}
return nil
}
@@ -340,12 +334,12 @@ func (d *Duration) UnmarshalText(text []byte) error {
}
// MarshalYAML implements the yaml.Marshaler interface.
-func (d Duration) MarshalYAML() (interface{}, error) {
+func (d Duration) MarshalYAML() (any, error) {
return d.String(), nil
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
-func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
+func (d *Duration) UnmarshalYAML(unmarshal func(any) error) error {
var s string
if err := unmarshal(&s); err != nil {
return err
diff --git a/vendor/github.com/prometheus/common/model/value.go b/vendor/github.com/prometheus/common/model/value.go
index a9995a37ee..8dffd9c4a5 100644
--- a/vendor/github.com/prometheus/common/model/value.go
+++ b/vendor/github.com/prometheus/common/model/value.go
@@ -259,13 +259,13 @@ func (s Scalar) String() string {
// MarshalJSON implements json.Marshaler.
func (s Scalar) MarshalJSON() ([]byte, error) {
v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64)
- return json.Marshal([...]interface{}{s.Timestamp, v})
+ return json.Marshal([...]any{s.Timestamp, v})
}
// UnmarshalJSON implements json.Unmarshaler.
func (s *Scalar) UnmarshalJSON(b []byte) error {
var f string
- v := [...]interface{}{&s.Timestamp, &f}
+ v := [...]any{&s.Timestamp, &f}
if err := json.Unmarshal(b, &v); err != nil {
return err
@@ -291,12 +291,12 @@ func (s *String) String() string {
// MarshalJSON implements json.Marshaler.
func (s String) MarshalJSON() ([]byte, error) {
- return json.Marshal([]interface{}{s.Timestamp, s.Value})
+ return json.Marshal([]any{s.Timestamp, s.Value})
}
// UnmarshalJSON implements json.Unmarshaler.
func (s *String) UnmarshalJSON(b []byte) error {
- v := [...]interface{}{&s.Timestamp, &s.Value}
+ v := [...]any{&s.Timestamp, &s.Value}
return json.Unmarshal(b, &v)
}
diff --git a/vendor/github.com/prometheus/common/model/value_float.go b/vendor/github.com/prometheus/common/model/value_float.go
index 6bfc757d18..b7d93615e2 100644
--- a/vendor/github.com/prometheus/common/model/value_float.go
+++ b/vendor/github.com/prometheus/common/model/value_float.go
@@ -79,7 +79,7 @@ func (s SamplePair) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
- return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil
+ return fmt.Appendf(nil, "[%s,%s]", t, v), nil
}
// UnmarshalJSON implements json.Unmarshaler.
diff --git a/vendor/github.com/prometheus/common/model/value_histogram.go b/vendor/github.com/prometheus/common/model/value_histogram.go
index 91ce5b7a45..f27856ccc4 100644
--- a/vendor/github.com/prometheus/common/model/value_histogram.go
+++ b/vendor/github.com/prometheus/common/model/value_histogram.go
@@ -67,11 +67,11 @@ func (s HistogramBucket) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
- return []byte(fmt.Sprintf("[%s,%s,%s,%s]", b, l, u, c)), nil
+ return fmt.Appendf(nil, "[%s,%s,%s,%s]", b, l, u, c), nil
}
func (s *HistogramBucket) UnmarshalJSON(buf []byte) error {
- tmp := []interface{}{&s.Boundaries, &s.Lower, &s.Upper, &s.Count}
+ tmp := []any{&s.Boundaries, &s.Lower, &s.Upper, &s.Count}
wantLen := len(tmp)
if err := json.Unmarshal(buf, &tmp); err != nil {
return err
@@ -152,11 +152,11 @@ func (s SampleHistogramPair) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
- return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil
+ return fmt.Appendf(nil, "[%s,%s]", t, v), nil
}
func (s *SampleHistogramPair) UnmarshalJSON(buf []byte) error {
- tmp := []interface{}{&s.Timestamp, &s.Histogram}
+ tmp := []any{&s.Timestamp, &s.Histogram}
wantLen := len(tmp)
if err := json.Unmarshal(buf, &tmp); err != nil {
return err
diff --git a/vendor/github.com/prometheus/procfs/.golangci.yml b/vendor/github.com/prometheus/procfs/.golangci.yml
index 3c3bf910fd..eac920ba80 100644
--- a/vendor/github.com/prometheus/procfs/.golangci.yml
+++ b/vendor/github.com/prometheus/procfs/.golangci.yml
@@ -1,7 +1,9 @@
version: "2"
linters:
enable:
+ - errorlint
- forbidigo
+ - gocritic
- godot
- misspell
- revive
@@ -11,6 +13,20 @@ linters:
forbid:
- pattern: ^fmt\.Print.*$
msg: Do not commit print statements.
+ gocritic:
+ enable-all: true
+ disabled-checks:
+ - commentFormatting
+ - commentedOutCode
+ - deferInLoop
+ - filepathJoin
+ - hugeParam
+ - importShadow
+ - paramTypeCombine
+ - rangeValCopy
+ - tooManyResultsChecker
+ - unnamedResult
+ - whyNoLint
godot:
exclude:
# Ignore "See: URL".
@@ -18,17 +34,21 @@ linters:
capital: true
misspell:
locale: US
+ revive:
+ rules:
+ - name: var-naming
+ # TODO(SuperQ): See: https://github.com/prometheus/prometheus/issues/17766
+ arguments:
+ - []
+ - []
+ - - skip-package-name-checks: true
exclusions:
- generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
- paths:
- - third_party$
- - builtin$
- - examples$
+ warn-unused: true
formatters:
enable:
- gofmt
@@ -37,9 +57,3 @@ formatters:
goimports:
local-prefixes:
- github.com/prometheus/procfs
- exclusions:
- generated: lax
- paths:
- - third_party$
- - builtin$
- - examples$
diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile
index 7edfe4d093..bce50a19c5 100644
--- a/vendor/github.com/prometheus/procfs/Makefile
+++ b/vendor/github.com/prometheus/procfs/Makefile
@@ -1,4 +1,4 @@
-# Copyright 2018 The Prometheus Authors
+# Copyright The Prometheus Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common
index 0ed55c2ba2..a7c5f553e1 100644
--- a/vendor/github.com/prometheus/procfs/Makefile.common
+++ b/vendor/github.com/prometheus/procfs/Makefile.common
@@ -1,4 +1,4 @@
-# Copyright 2018 The Prometheus Authors
+# Copyright The Prometheus Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
@@ -33,7 +33,7 @@ GOHOSTOS ?= $(shell $(GO) env GOHOSTOS)
GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH)
GO_VERSION ?= $(shell $(GO) version)
-GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))Error Parsing File
+GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
PROMU := $(FIRST_GOPATH)/bin/promu
@@ -55,13 +55,14 @@ ifneq ($(shell command -v gotestsum 2> /dev/null),)
endif
endif
-PROMU_VERSION ?= 0.17.0
+PROMU_VERSION ?= 0.20.0
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
SKIP_GOLANGCI_LINT :=
GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?=
-GOLANGCI_LINT_VERSION ?= v2.0.2
+GOLANGCI_LINT_VERSION ?= v2.11.4
+GOLANGCI_FMT_OPTS ?=
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
@@ -81,11 +82,32 @@ endif
PREFIX ?= $(shell pwd)
BIN_DIR ?= $(shell pwd)
DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
-DOCKERFILE_PATH ?= ./Dockerfile
DOCKERBUILD_CONTEXT ?= ./
DOCKER_REPO ?= prom
-DOCKER_ARCHS ?= amd64
+# Check if deprecated DOCKERFILE_PATH is set
+ifdef DOCKERFILE_PATH
+$(error DOCKERFILE_PATH is deprecated. Use DOCKERFILE_VARIANTS ?= $(DOCKERFILE_PATH) in the Makefile)
+endif
+
+DOCKER_ARCHS ?= amd64 arm64 armv7 ppc64le riscv64 s390x
+DOCKERFILE_VARIANTS ?= $(wildcard Dockerfile Dockerfile.*)
+
+# Function to extract variant from Dockerfile label.
+# Returns the variant name from io.prometheus.image.variant label, or "default" if not found.
+define dockerfile_variant
+$(strip $(or $(shell sed -n 's/.*io\.prometheus\.image\.variant="\([^"]*\)".*/\1/p' $(1)),default))
+endef
+
+# Check for duplicate variant names (including default for Dockerfiles without labels).
+DOCKERFILE_VARIANT_NAMES := $(foreach df,$(DOCKERFILE_VARIANTS),$(call dockerfile_variant,$(df)))
+DOCKERFILE_VARIANT_NAMES_SORTED := $(sort $(DOCKERFILE_VARIANT_NAMES))
+ifneq ($(words $(DOCKERFILE_VARIANT_NAMES)),$(words $(DOCKERFILE_VARIANT_NAMES_SORTED)))
+$(error Duplicate variant names found. Each Dockerfile must have a unique io.prometheus.image.variant label, and only one can be without a label (default))
+endif
+
+# Build variant:dockerfile pairs for shell iteration.
+DOCKERFILE_VARIANTS_WITH_NAMES := $(foreach df,$(DOCKERFILE_VARIANTS),$(call dockerfile_variant,$(df)):$(df))
BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS))
PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS))
@@ -111,7 +133,7 @@ common-all: precheck style check_license lint yamllint unused build test
.PHONY: common-style
common-style:
@echo ">> checking code style"
- @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \
+ @fmtRes=$$($(GOFMT) -d $$(git ls-files '*.go' ':!:vendor/*' || find . -path ./vendor -prune -o -name '*.go' -print)); \
if [ -n "$${fmtRes}" ]; then \
echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \
echo "Please ensure you are using $$($(GO) version) for formatting code."; \
@@ -121,13 +143,19 @@ common-style:
.PHONY: common-check_license
common-check_license:
@echo ">> checking license header"
- @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \
+ @licRes=$$(for file in $$(git ls-files '*.go' ':!:vendor/*' || find . -path ./vendor -prune -o -type f -iname '*.go' -print) ; do \
awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \
done); \
if [ -n "$${licRes}" ]; then \
echo "license header checking failed:"; echo "$${licRes}"; \
exit 1; \
fi
+ @echo ">> checking for copyright years 2026 or later"
+ @futureYearRes=$$(git grep -E 'Copyright (202[6-9]|20[3-9][0-9])' -- '*.go' ':!:vendor/*' || true); \
+ if [ -n "$${futureYearRes}" ]; then \
+ echo "Files with copyright year 2026 or later found (should use 'Copyright The Prometheus Authors'):"; echo "$${futureYearRes}"; \
+ exit 1; \
+ fi
.PHONY: common-deps
common-deps:
@@ -138,7 +166,7 @@ common-deps:
update-go-deps:
@echo ">> updating Go dependencies"
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
- $(GO) get -d $$m; \
+ $(GO) get $$m; \
done
$(GO) mod tidy
@@ -156,9 +184,13 @@ $(GOTEST_DIR):
@mkdir -p $@
.PHONY: common-format
-common-format:
+common-format: $(GOLANGCI_LINT)
@echo ">> formatting code"
$(GO) fmt $(pkgs)
+ifdef GOLANGCI_LINT
+ @echo ">> formatting code with golangci-lint"
+ $(GOLANGCI_LINT) fmt $(GOLANGCI_FMT_OPTS)
+endif
.PHONY: common-vet
common-vet:
@@ -215,28 +247,142 @@ common-docker-repo-name:
.PHONY: common-docker $(BUILD_DOCKER_ARCHS)
common-docker: $(BUILD_DOCKER_ARCHS)
$(BUILD_DOCKER_ARCHS): common-docker-%:
- docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \
- -f $(DOCKERFILE_PATH) \
- --build-arg ARCH="$*" \
- --build-arg OS="linux" \
- $(DOCKERBUILD_CONTEXT)
+ @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
+ dockerfile=$${variant#*:}; \
+ variant_name=$${variant%%:*}; \
+ distroless_arch="$*"; \
+ if [ "$*" = "armv7" ]; then \
+ distroless_arch="arm"; \
+ fi; \
+ if [ "$$dockerfile" = "Dockerfile" ]; then \
+ echo "Building default variant ($$variant_name) for linux-$* using $$dockerfile"; \
+ docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \
+ -f $$dockerfile \
+ --build-arg ARCH="$*" \
+ --build-arg OS="linux" \
+ --build-arg DISTROLESS_ARCH="$$distroless_arch" \
+ $(DOCKERBUILD_CONTEXT); \
+ if [ "$$variant_name" != "default" ]; then \
+ echo "Tagging default variant with $$variant_name suffix"; \
+ docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \
+ "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \
+ fi; \
+ else \
+ echo "Building $$variant_name variant for linux-$* using $$dockerfile"; \
+ docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" \
+ -f $$dockerfile \
+ --build-arg ARCH="$*" \
+ --build-arg OS="linux" \
+ --build-arg DISTROLESS_ARCH="$$distroless_arch" \
+ $(DOCKERBUILD_CONTEXT); \
+ fi; \
+ done
.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
- docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)"
+ @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
+ dockerfile=$${variant#*:}; \
+ variant_name=$${variant%%:*}; \
+ if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
+ echo "Pushing $$variant_name variant for linux-$*"; \
+ docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \
+ fi; \
+ if [ "$$dockerfile" = "Dockerfile" ]; then \
+ echo "Pushing default variant ($$variant_name) for linux-$*"; \
+ docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)"; \
+ fi; \
+ if [ "$(DOCKER_IMAGE_TAG)" = "latest" ]; then \
+ if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
+ echo "Pushing $$variant_name variant version tags for linux-$*"; \
+ docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \
+ fi; \
+ if [ "$$dockerfile" = "Dockerfile" ]; then \
+ echo "Pushing default variant version tag for linux-$*"; \
+ docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"; \
+ fi; \
+ fi; \
+ done
DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION)))
.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
- docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
- docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"
+ @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
+ dockerfile=$${variant#*:}; \
+ variant_name=$${variant%%:*}; \
+ if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
+ echo "Tagging $$variant_name variant for linux-$* as latest"; \
+ docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest-$$variant_name"; \
+ docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \
+ fi; \
+ if [ "$$dockerfile" = "Dockerfile" ]; then \
+ echo "Tagging default variant ($$variant_name) for linux-$* as latest"; \
+ docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"; \
+ docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"; \
+ fi; \
+ done
.PHONY: common-docker-manifest
common-docker-manifest:
- DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(SANITIZED_DOCKER_IMAGE_TAG))
- DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)"
+ @for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
+ dockerfile=$${variant#*:}; \
+ variant_name=$${variant%%:*}; \
+ if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
+ echo "Creating manifest for $$variant_name variant"; \
+ refs=""; \
+ for arch in $(DOCKER_ARCHS); do \
+ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \
+ done; \
+ if [ -z "$$refs" ]; then \
+ echo "Skipping manifest for $$variant_name variant (no supported architectures)"; \
+ continue; \
+ fi; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" $$refs; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \
+ fi; \
+ if [ "$$dockerfile" = "Dockerfile" ]; then \
+ echo "Creating default variant ($$variant_name) manifest"; \
+ refs=""; \
+ for arch in $(DOCKER_ARCHS); do \
+ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:$(SANITIZED_DOCKER_IMAGE_TAG)"; \
+ done; \
+ if [ -z "$$refs" ]; then \
+ echo "Skipping default variant manifest (no supported architectures)"; \
+ continue; \
+ fi; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" $$refs; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)"; \
+ fi; \
+ if [ "$(DOCKER_IMAGE_TAG)" = "latest" ]; then \
+ if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
+ echo "Creating manifest for $$variant_name variant version tag"; \
+ refs=""; \
+ for arch in $(DOCKER_ARCHS); do \
+ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \
+ done; \
+ if [ -z "$$refs" ]; then \
+ echo "Skipping version-tag manifest for $$variant_name variant (no supported architectures)"; \
+ continue; \
+ fi; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name" $$refs; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \
+ fi; \
+ if [ "$$dockerfile" = "Dockerfile" ]; then \
+ echo "Creating default variant version tag manifest"; \
+ refs=""; \
+ for arch in $(DOCKER_ARCHS); do \
+ refs="$$refs $(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$$arch:v$(DOCKER_MAJOR_VERSION_TAG)"; \
+ done; \
+ if [ -z "$$refs" ]; then \
+ echo "Skipping default variant version-tag manifest (no supported architectures)"; \
+ continue; \
+ fi; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)" $$refs; \
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)"; \
+ fi; \
+ fi; \
+ done
.PHONY: promu
promu: $(PROMU)
@@ -248,8 +394,8 @@ $(PROMU):
cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
rm -r $(PROMU_TMP)
-.PHONY: proto
-proto:
+.PHONY: common-proto
+common-proto:
@echo ">> generating code from proto files"
@./scripts/genproto.sh
@@ -261,6 +407,10 @@ $(GOLANGCI_LINT):
| sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
endif
+.PHONY: common-print-golangci-lint-version
+common-print-golangci-lint-version:
+ @echo $(GOLANGCI_LINT_VERSION)
+
.PHONY: precheck
precheck::
@@ -275,9 +425,3 @@ $(1)_precheck:
exit 1; \
fi
endef
-
-govulncheck: install-govulncheck
- govulncheck ./...
-
-install-govulncheck:
- command -v govulncheck > /dev/null || go install golang.org/x/vuln/cmd/govulncheck@latest
diff --git a/vendor/github.com/prometheus/procfs/README.md b/vendor/github.com/prometheus/procfs/README.md
index 0718239cf1..363524094b 100644
--- a/vendor/github.com/prometheus/procfs/README.md
+++ b/vendor/github.com/prometheus/procfs/README.md
@@ -7,7 +7,7 @@ metrics from the pseudo-filesystems /proc and /sys.
backwards-incompatible ways without warnings. Use it at your own risk.
[](https://pkg.go.dev/github.com/prometheus/procfs)
-[](https://circleci.com/gh/prometheus/procfs/tree/master)
+[](https://github.com/prometheus/procfs/actions/workflows/ci.yml)
[](https://goreportcard.com/report/github.com/prometheus/procfs)
## Usage
diff --git a/vendor/github.com/prometheus/procfs/SECURITY.md b/vendor/github.com/prometheus/procfs/SECURITY.md
index fed02d85c7..5e6f976dbf 100644
--- a/vendor/github.com/prometheus/procfs/SECURITY.md
+++ b/vendor/github.com/prometheus/procfs/SECURITY.md
@@ -3,4 +3,4 @@
The Prometheus security policy, including how to report vulnerabilities, can be
found here:
-
+[https://prometheus.io/docs/operating/security/](https://prometheus.io/docs/operating/security/)
diff --git a/vendor/github.com/prometheus/procfs/arp.go b/vendor/github.com/prometheus/procfs/arp.go
index 2e53344151..716bdef109 100644
--- a/vendor/github.com/prometheus/procfs/arp.go
+++ b/vendor/github.com/prometheus/procfs/arp.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -73,15 +73,16 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) {
columns := strings.Fields(line)
width := len(columns)
- if width == expectedHeaderWidth || width == 0 {
+ switch width {
+ case expectedHeaderWidth, 0:
continue
- } else if width == expectedDataWidth {
+ case expectedDataWidth:
entry, err := parseARPEntry(columns)
if err != nil {
return []ARPEntry{}, fmt.Errorf("%w: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err)
}
entries = append(entries, entry)
- } else {
+ default:
return []ARPEntry{}, fmt.Errorf("%w: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err)
}
diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go
index 8380750090..53243e6875 100644
--- a/vendor/github.com/prometheus/procfs/buddyinfo.go
+++ b/vendor/github.com/prometheus/procfs/buddyinfo.go
@@ -1,4 +1,4 @@
-// Copyright 2017 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -64,14 +64,12 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
if bucketCount == -1 {
bucketCount = arraySize
- } else {
- if bucketCount != arraySize {
- return nil, fmt.Errorf("%w: mismatch in number of buddyinfo buckets, previous count %d, new count %d", ErrFileParse, bucketCount, arraySize)
- }
+ } else if bucketCount != arraySize {
+ return nil, fmt.Errorf("%w: mismatch in number of buddyinfo buckets, previous count %d, new count %d", ErrFileParse, bucketCount, arraySize)
}
sizes := make([]float64, arraySize)
- for i := 0; i < arraySize; i++ {
+ for i := range arraySize {
sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
if err != nil {
return nil, fmt.Errorf("%w: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err)
diff --git a/vendor/github.com/prometheus/procfs/cmdline.go b/vendor/github.com/prometheus/procfs/cmdline.go
index bf4f3b48c0..4f1cac1f0a 100644
--- a/vendor/github.com/prometheus/procfs/cmdline.go
+++ b/vendor/github.com/prometheus/procfs/cmdline.go
@@ -1,4 +1,4 @@
-// Copyright 2021 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo.go b/vendor/github.com/prometheus/procfs/cpuinfo.go
index f0950bb495..4b23d8d6b5 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build linux
-// +build linux
package procfs
@@ -502,7 +501,7 @@ func parseCPUInfoRISCV(info []byte) ([]CPUInfo, error) {
return cpuinfo, nil
}
-func parseCPUInfoDummy(_ []byte) ([]CPUInfo, error) { // nolint:unused,deadcode
+func parseCPUInfoDummy(_ []byte) ([]CPUInfo, error) { //nolint:unused
return nil, errors.New("not implemented")
}
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_armx.go b/vendor/github.com/prometheus/procfs/cpuinfo_armx.go
index 64cfd534c1..b09035ff38 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_armx.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_armx.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,8 +12,6 @@
// limitations under the License.
//go:build linux && (arm || arm64)
-// +build linux
-// +build arm arm64
package procfs
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_loong64.go b/vendor/github.com/prometheus/procfs/cpuinfo_loong64.go
index d88442f0ed..7bb20211f9 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_loong64.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_loong64.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build linux
-// +build linux
package procfs
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go b/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go
index c11207f3ab..fd75d0f79d 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,8 +12,6 @@
// limitations under the License.
//go:build linux && (mips || mipsle || mips64 || mips64le)
-// +build linux
-// +build mips mipsle mips64 mips64le
package procfs
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_others.go b/vendor/github.com/prometheus/procfs/cpuinfo_others.go
index a6b2b3127c..3d36ba0e6b 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_others.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_others.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build linux && !386 && !amd64 && !arm && !arm64 && !loong64 && !mips && !mips64 && !mips64le && !mipsle && !ppc64 && !ppc64le && !riscv64 && !s390x
-// +build linux,!386,!amd64,!arm,!arm64,!loong64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x
package procfs
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go b/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go
index 003bc2ad4a..b3425051ef 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,8 +12,6 @@
// limitations under the License.
//go:build linux && (ppc64 || ppc64le)
-// +build linux
-// +build ppc64 ppc64le
package procfs
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go b/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go
index 1c9b7313b6..72598230c3 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,8 +12,6 @@
// limitations under the License.
//go:build linux && (riscv || riscv64)
-// +build linux
-// +build riscv riscv64
package procfs
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go b/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go
index fa3686bc00..50a8239cbc 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build linux
-// +build linux
package procfs
diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_x86.go b/vendor/github.com/prometheus/procfs/cpuinfo_x86.go
index a0ef55562e..00edb30a5c 100644
--- a/vendor/github.com/prometheus/procfs/cpuinfo_x86.go
+++ b/vendor/github.com/prometheus/procfs/cpuinfo_x86.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,8 +12,6 @@
// limitations under the License.
//go:build linux && (386 || amd64)
-// +build linux
-// +build 386 amd64
package procfs
diff --git a/vendor/github.com/prometheus/procfs/crypto.go b/vendor/github.com/prometheus/procfs/crypto.go
index 5f2a37a78b..d93b712e05 100644
--- a/vendor/github.com/prometheus/procfs/crypto.go
+++ b/vendor/github.com/prometheus/procfs/crypto.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -48,11 +48,13 @@ type Crypto struct {
Walksize *uint64
}
+var cryptoFile = "crypto"
+
// Crypto parses an crypto-file (/proc/crypto) and returns a slice of
// structs containing the relevant info. More information available here:
// https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html
func (fs FS) Crypto() ([]Crypto, error) {
- path := fs.proc.Path("crypto")
+ path := fs.proc.Path(cryptoFile)
b, err := util.ReadFileNoStat(path)
if err != nil {
return nil, fmt.Errorf("%w: Cannot read file %v: %w", ErrFileRead, b, err)
@@ -82,6 +84,10 @@ func parseCrypto(r io.Reader) ([]Crypto, error) {
continue
}
+ if len(out) == 0 {
+ return nil, fmt.Errorf("%w: parsed invalid line before name parsed: %q", ErrFileParse, text)
+ }
+
kv := strings.Split(text, ":")
if len(kv) != 2 {
return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, text)
diff --git a/vendor/github.com/prometheus/procfs/doc.go b/vendor/github.com/prometheus/procfs/doc.go
index f9d961e441..26bfea071b 100644
--- a/vendor/github.com/prometheus/procfs/doc.go
+++ b/vendor/github.com/prometheus/procfs/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2014 Prometheus Team
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/fs.go b/vendor/github.com/prometheus/procfs/fs.go
index 9bdaccc7c8..8f27912a13 100644
--- a/vendor/github.com/prometheus/procfs/fs.go
+++ b/vendor/github.com/prometheus/procfs/fs.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/fs_statfs_notype.go b/vendor/github.com/prometheus/procfs/fs_statfs_notype.go
index 1b5bdbdf84..0bef25bdd9 100644
--- a/vendor/github.com/prometheus/procfs/fs_statfs_notype.go
+++ b/vendor/github.com/prometheus/procfs/fs_statfs_notype.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !freebsd && !linux
-// +build !freebsd,!linux
package procfs
diff --git a/vendor/github.com/prometheus/procfs/fs_statfs_type.go b/vendor/github.com/prometheus/procfs/fs_statfs_type.go
index 80df79c319..d183330390 100644
--- a/vendor/github.com/prometheus/procfs/fs_statfs_type.go
+++ b/vendor/github.com/prometheus/procfs/fs_statfs_type.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build freebsd || linux
-// +build freebsd linux
package procfs
diff --git a/vendor/github.com/prometheus/procfs/fscache.go b/vendor/github.com/prometheus/procfs/fscache.go
index 7db8633077..9dde857073 100644
--- a/vendor/github.com/prometheus/procfs/fscache.go
+++ b/vendor/github.com/prometheus/procfs/fscache.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -388,20 +388,21 @@ func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) {
}
}
case "CacheOp:":
- if strings.Split(fields[1], "=")[0] == "alo" {
+ switch strings.Split(fields[1], "=")[0] {
+ case "alo":
err := setFSCacheFields(fields[1:], &m.CacheopAllocationsinProgress, &m.CacheopLookupObjectInProgress,
&m.CacheopLookupCompleteInPorgress, &m.CacheopGrabObjectInProgress)
if err != nil {
return &m, err
}
- } else if strings.Split(fields[1], "=")[0] == "inv" {
+ case "inv":
err := setFSCacheFields(fields[1:], &m.CacheopInvalidations, &m.CacheopUpdateObjectInProgress,
&m.CacheopDropObjectInProgress, &m.CacheopPutObjectInProgress, &m.CacheopAttributeChangeInProgress,
&m.CacheopSyncCacheInProgress)
if err != nil {
return &m, err
}
- } else {
+ default:
err := setFSCacheFields(fields[1:], &m.CacheopReadOrAllocPageInProgress, &m.CacheopReadOrAllocPagesInProgress,
&m.CacheopAllocatePageInProgress, &m.CacheopAllocatePagesInProgress, &m.CacheopWritePagesInProgress,
&m.CacheopUncachePagesInProgress, &m.CacheopDissociatePagesInProgress)
diff --git a/vendor/github.com/prometheus/procfs/internal/fs/fs.go b/vendor/github.com/prometheus/procfs/internal/fs/fs.go
index 3a43e83915..e7ccad66b2 100644
--- a/vendor/github.com/prometheus/procfs/internal/fs/fs.go
+++ b/vendor/github.com/prometheus/procfs/internal/fs/fs.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go
index 5a7d2df06a..30c5872019 100644
--- a/vendor/github.com/prometheus/procfs/internal/util/parse.go
+++ b/vendor/github.com/prometheus/procfs/internal/util/parse.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/internal/util/readfile.go b/vendor/github.com/prometheus/procfs/internal/util/readfile.go
index 71b7a70ebd..0e41f71af1 100644
--- a/vendor/github.com/prometheus/procfs/internal/util/readfile.go
+++ b/vendor/github.com/prometheus/procfs/internal/util/readfile.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go
index d5404a6d72..f6a4a4de62 100644
--- a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go
+++ b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,8 +12,6 @@
// limitations under the License.
//go:build (linux || darwin) && !appengine
-// +build linux darwin
-// +build !appengine
package util
diff --git a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go
index 1d86f5e63f..c80e082cb9 100644
--- a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go
+++ b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build (linux && appengine) || (!linux && !darwin)
-// +build linux,appengine !linux,!darwin
package util
diff --git a/vendor/github.com/prometheus/procfs/internal/util/valueparser.go b/vendor/github.com/prometheus/procfs/internal/util/valueparser.go
index fe2355d3c6..e0ed671ea0 100644
--- a/vendor/github.com/prometheus/procfs/internal/util/valueparser.go
+++ b/vendor/github.com/prometheus/procfs/internal/util/valueparser.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go
index bc3a20c932..5374da9fa8 100644
--- a/vendor/github.com/prometheus/procfs/ipvs.go
+++ b/vendor/github.com/prometheus/procfs/ipvs.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/kernel_hung.go b/vendor/github.com/prometheus/procfs/kernel_hung.go
new file mode 100644
index 0000000000..0c7a69f99f
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/kernel_hung.go
@@ -0,0 +1,44 @@
+// Copyright The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build !windows
+
+package procfs
+
+import (
+ "os"
+ "strconv"
+ "strings"
+)
+
+// KernelHung contains information about to the kernel's hung_task_detect_count number.
+type KernelHung struct {
+ // Indicates the total number of tasks that have been detected as hung since the system boot.
+ // This file shows up if `CONFIG_DETECT_HUNG_TASK` is enabled.
+ HungTaskDetectCount *uint64
+}
+
+// KernelHung returns values from /proc/sys/kernel/hung_task_detect_count.
+func (fs FS) KernelHung() (KernelHung, error) {
+ data, err := os.ReadFile(fs.proc.Path("sys", "kernel", "hung_task_detect_count"))
+ if err != nil {
+ return KernelHung{}, err
+ }
+ val, err := strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
+ if err != nil {
+ return KernelHung{}, err
+ }
+ return KernelHung{
+ HungTaskDetectCount: &val,
+ }, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/kernel_random.go b/vendor/github.com/prometheus/procfs/kernel_random.go
index db88566bdf..e7c5b8cf2b 100644
--- a/vendor/github.com/prometheus/procfs/kernel_random.go
+++ b/vendor/github.com/prometheus/procfs/kernel_random.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !windows
-// +build !windows
package procfs
diff --git a/vendor/github.com/prometheus/procfs/loadavg.go b/vendor/github.com/prometheus/procfs/loadavg.go
index 332e76c17f..c8c78a65ed 100644
--- a/vendor/github.com/prometheus/procfs/loadavg.go
+++ b/vendor/github.com/prometheus/procfs/loadavg.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go
index 67a9d2b448..d66eeda82a 100644
--- a/vendor/github.com/prometheus/procfs/mdstat.go
+++ b/vendor/github.com/prometheus/procfs/mdstat.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -27,13 +27,34 @@ var (
recoveryLinePctRE = regexp.MustCompile(`= (.+)%`)
recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`)
recoveryLineSpeedRE = regexp.MustCompile(`speed=(.+)[A-Z]`)
- componentDeviceRE = regexp.MustCompile(`(.*)\[\d+\]`)
+ componentDeviceRE = regexp.MustCompile(`(.*)\[(\d+)\](\([SF]+\))?`)
+ personalitiesPrefix = "Personalities : "
)
+type MDStatComponent struct {
+ // Name of the component device.
+ Name string
+ // DescriptorIndex number of component device, e.g. the order in the superblock.
+ DescriptorIndex int32
+ // Flags per Linux drivers/md/md.[ch] as of v6.12-rc1
+ // Subset that are exposed in mdstat
+ WriteMostly bool
+ Journal bool
+ Faulty bool // "Faulty" is what kernel source uses for "(F)"
+ Spare bool
+ Replacement bool
+ // Some additional flags that are NOT exposed in procfs today; they may
+ // be available via sysfs.
+ // In_sync, Bitmap_sync, Blocked, WriteErrorSeen, FaultRecorded,
+ // BlockedBadBlocks, WantReplacement, Candidate, ...
+}
+
// MDStat holds info parsed from /proc/mdstat.
type MDStat struct {
// Name of the device.
Name string
+ // raid type of the device.
+ Type string
// activity-state of the device.
ActivityState string
// Number of active disks.
@@ -58,8 +79,8 @@ type MDStat struct {
BlocksSyncedFinishTime float64
// current sync speed (in Kilobytes/sec)
BlocksSyncedSpeed float64
- // Name of md component devices
- Devices []string
+ // component devices
+ Devices []MDStatComponent
}
// MDStat parses an mdstat-file (/proc/mdstat) and returns a slice of
@@ -80,28 +101,52 @@ func (fs FS) MDStat() ([]MDStat, error) {
// parseMDStat parses data from mdstat file (/proc/mdstat) and returns a slice of
// structs containing the relevant info.
func parseMDStat(mdStatData []byte) ([]MDStat, error) {
+ // TODO:
+ // - parse global hotspares from the "unused devices" line.
mdStats := []MDStat{}
lines := strings.Split(string(mdStatData), "\n")
+ knownRaidTypes := make(map[string]bool)
for i, line := range lines {
if strings.TrimSpace(line) == "" || line[0] == ' ' ||
- strings.HasPrefix(line, "Personalities") ||
strings.HasPrefix(line, "unused") {
continue
}
+ // Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
+ if len(knownRaidTypes) == 0 && strings.HasPrefix(line, personalitiesPrefix) {
+ personalities := strings.Fields(line[len(personalitiesPrefix):])
+ for _, word := range personalities {
+ word := word[1 : len(word)-1]
+ knownRaidTypes[word] = true
+ }
+ continue
+ }
deviceFields := strings.Fields(line)
if len(deviceFields) < 3 {
return nil, fmt.Errorf("%w: Expected 3+ lines, got %q", ErrFileParse, line)
}
mdName := deviceFields[0] // mdx
- state := deviceFields[2] // active or inactive
+ state := deviceFields[2] // active, inactive, broken
+
+ mdType := "unknown" // raid1, raid5, etc.
+ var deviceStartIndex int
+ if len(deviceFields) > 3 { // mdType may be in the 3rd or 4th field
+ if isRaidType(deviceFields[3], knownRaidTypes) {
+ mdType = deviceFields[3]
+ deviceStartIndex = 4
+ } else if len(deviceFields) > 4 && isRaidType(deviceFields[4], knownRaidTypes) {
+ // if the 3rd field is (...), the 4th field is the mdType
+ mdType = deviceFields[4]
+ deviceStartIndex = 5
+ }
+ }
if len(lines) <= i+3 {
return nil, fmt.Errorf("%w: Too few lines for md device: %q", ErrFileParse, mdName)
}
- // Failed disks have the suffix (F) & Spare disks have the suffix (S).
+ // Failed (Faulty) disks have the suffix (F) & Spare disks have the suffix (S).
fail := int64(strings.Count(line, "(F)"))
spare := int64(strings.Count(line, "(S)"))
active, total, down, size, err := evalStatusLine(lines[i], lines[i+1])
@@ -123,16 +168,20 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
finish := float64(0)
pct := float64(0)
recovering := strings.Contains(lines[syncLineIdx], "recovery")
+ reshaping := strings.Contains(lines[syncLineIdx], "reshape")
resyncing := strings.Contains(lines[syncLineIdx], "resync")
checking := strings.Contains(lines[syncLineIdx], "check")
// Append recovery and resyncing state info.
- if recovering || resyncing || checking {
- if recovering {
+ if recovering || resyncing || checking || reshaping {
+ switch {
+ case recovering:
state = "recovering"
- } else if checking {
+ case reshaping:
+ state = "reshaping"
+ case checking:
state = "checking"
- } else {
+ default:
state = "resyncing"
}
@@ -148,8 +197,14 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
}
}
+ devices, err := evalComponentDevices(deviceFields[deviceStartIndex:])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing components in md device %q: %w", mdName, err)
+ }
+
mdStats = append(mdStats, MDStat{
Name: mdName,
+ Type: mdType,
ActivityState: state,
DisksActive: active,
DisksFailed: fail,
@@ -162,14 +217,24 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
BlocksSyncedPct: pct,
BlocksSyncedFinishTime: finish,
BlocksSyncedSpeed: speed,
- Devices: evalComponentDevices(deviceFields),
+ Devices: devices,
})
}
return mdStats, nil
}
+// check if a string's format is like the mdType
+// Rule 1: mdType should not be like (...)
+// Rule 2: mdType should not be like sda[0]
+// .
+func isRaidType(mdType string, knownRaidTypes map[string]bool) bool {
+ _, ok := knownRaidTypes[mdType]
+ return !strings.ContainsAny(mdType, "([") && ok
+}
+
func evalStatusLine(deviceLine, statusLine string) (active, total, down, size int64, err error) {
+ // e.g. 523968 blocks super 1.2 [4/4] [UUUU]
statusFields := strings.Fields(statusLine)
if len(statusFields) < 1 {
return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected statusline %q: %w", ErrFileParse, statusLine, err)
@@ -260,17 +325,29 @@ func evalRecoveryLine(recoveryLine string) (blocksSynced int64, blocksToBeSynced
return blocksSynced, blocksToBeSynced, pct, finish, speed, nil
}
-func evalComponentDevices(deviceFields []string) []string {
- mdComponentDevices := make([]string, 0)
- if len(deviceFields) > 3 {
- for _, field := range deviceFields[4:] {
- match := componentDeviceRE.FindStringSubmatch(field)
- if match == nil {
- continue
- }
- mdComponentDevices = append(mdComponentDevices, match[1])
+func evalComponentDevices(deviceFields []string) ([]MDStatComponent, error) {
+ mdComponentDevices := make([]MDStatComponent, 0)
+ for _, field := range deviceFields {
+ match := componentDeviceRE.FindStringSubmatch(field)
+ if match == nil {
+ continue
+ }
+ descriptorIndex, err := strconv.ParseInt(match[2], 10, 32)
+ if err != nil {
+ return mdComponentDevices, fmt.Errorf("error parsing int from device %q: %w", match[2], err)
}
+ mdComponentDevices = append(mdComponentDevices, MDStatComponent{
+ Name: match[1],
+ DescriptorIndex: int32(descriptorIndex),
+ // match may contain one or more of these
+ // https://github.com/torvalds/linux/blob/7ec462100ef9142344ddbf86f2c3008b97acddbe/drivers/md/md.c#L8376-L8392
+ Faulty: strings.Contains(match[3], "(F)"),
+ Spare: strings.Contains(match[3], "(S)"),
+ Journal: strings.Contains(match[3], "(J)"),
+ Replacement: strings.Contains(match[3], "(R)"),
+ WriteMostly: strings.Contains(match[3], "(W)"),
+ })
}
- return mdComponentDevices
+ return mdComponentDevices, nil
}
diff --git a/vendor/github.com/prometheus/procfs/meminfo.go b/vendor/github.com/prometheus/procfs/meminfo.go
index 4b2c4050a3..3420383187 100644
--- a/vendor/github.com/prometheus/procfs/meminfo.go
+++ b/vendor/github.com/prometheus/procfs/meminfo.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -66,6 +66,10 @@ type Meminfo struct {
// Memory which has been evicted from RAM, and is temporarily
// on the disk
SwapFree *uint64
+ // Memory consumed by the zswap backend (compressed size)
+ Zswap *uint64
+ // Amount of anonymous memory stored in zswap (original size)
+ Zswapped *uint64
// Memory which is waiting to get written back to the disk
Dirty *uint64
// Memory which is actively being written back to the disk
@@ -85,6 +89,8 @@ type Meminfo struct {
// amount of memory dedicated to the lowest level of page
// tables.
PageTables *uint64
+ // secondary page tables.
+ SecPageTables *uint64
// NFS pages sent to the server, but not yet committed to
// stable storage
NFSUnstable *uint64
@@ -129,15 +135,18 @@ type Meminfo struct {
Percpu *uint64
HardwareCorrupted *uint64
AnonHugePages *uint64
+ FileHugePages *uint64
ShmemHugePages *uint64
ShmemPmdMapped *uint64
CmaTotal *uint64
CmaFree *uint64
+ Unaccepted *uint64
HugePagesTotal *uint64
HugePagesFree *uint64
HugePagesRsvd *uint64
HugePagesSurp *uint64
Hugepagesize *uint64
+ Hugetlb *uint64
DirectMap4k *uint64
DirectMap2M *uint64
DirectMap1G *uint64
@@ -161,6 +170,8 @@ type Meminfo struct {
MlockedBytes *uint64
SwapTotalBytes *uint64
SwapFreeBytes *uint64
+ ZswapBytes *uint64
+ ZswappedBytes *uint64
DirtyBytes *uint64
WritebackBytes *uint64
AnonPagesBytes *uint64
@@ -171,6 +182,7 @@ type Meminfo struct {
SUnreclaimBytes *uint64
KernelStackBytes *uint64
PageTablesBytes *uint64
+ SecPageTablesBytes *uint64
NFSUnstableBytes *uint64
BounceBytes *uint64
WritebackTmpBytes *uint64
@@ -182,11 +194,14 @@ type Meminfo struct {
PercpuBytes *uint64
HardwareCorruptedBytes *uint64
AnonHugePagesBytes *uint64
+ FileHugePagesBytes *uint64
ShmemHugePagesBytes *uint64
ShmemPmdMappedBytes *uint64
CmaTotalBytes *uint64
CmaFreeBytes *uint64
+ UnacceptedBytes *uint64
HugepagesizeBytes *uint64
+ HugetlbBytes *uint64
DirectMap4kBytes *uint64
DirectMap2MBytes *uint64
DirectMap1GBytes *uint64
@@ -287,6 +302,12 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
case "SwapFree:":
m.SwapFree = &val
m.SwapFreeBytes = &valBytes
+ case "Zswap:":
+ m.Zswap = &val
+ m.ZswapBytes = &valBytes
+ case "Zswapped:":
+ m.Zswapped = &val
+ m.ZswappedBytes = &valBytes
case "Dirty:":
m.Dirty = &val
m.DirtyBytes = &valBytes
@@ -317,6 +338,9 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
case "PageTables:":
m.PageTables = &val
m.PageTablesBytes = &valBytes
+ case "SecPageTables:":
+ m.SecPageTables = &val
+ m.SecPageTablesBytes = &valBytes
case "NFS_Unstable:":
m.NFSUnstable = &val
m.NFSUnstableBytes = &valBytes
@@ -350,6 +374,9 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
case "AnonHugePages:":
m.AnonHugePages = &val
m.AnonHugePagesBytes = &valBytes
+ case "FileHugePages:":
+ m.FileHugePages = &val
+ m.FileHugePagesBytes = &valBytes
case "ShmemHugePages:":
m.ShmemHugePages = &val
m.ShmemHugePagesBytes = &valBytes
@@ -362,6 +389,9 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
case "CmaFree:":
m.CmaFree = &val
m.CmaFreeBytes = &valBytes
+ case "Unaccepted:":
+ m.Unaccepted = &val
+ m.UnacceptedBytes = &valBytes
case "HugePages_Total:":
m.HugePagesTotal = &val
case "HugePages_Free:":
@@ -373,6 +403,9 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
case "Hugepagesize:":
m.Hugepagesize = &val
m.HugepagesizeBytes = &valBytes
+ case "Hugetlb:":
+ m.Hugetlb = &val
+ m.HugetlbBytes = &valBytes
case "DirectMap4k:":
m.DirectMap4k = &val
m.DirectMap4kBytes = &valBytes
diff --git a/vendor/github.com/prometheus/procfs/mountinfo.go b/vendor/github.com/prometheus/procfs/mountinfo.go
index a704c5e735..8594ae7f1e 100644
--- a/vendor/github.com/prometheus/procfs/mountinfo.go
+++ b/vendor/github.com/prometheus/procfs/mountinfo.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -17,10 +17,10 @@ import (
"bufio"
"bytes"
"fmt"
+ "io"
+ "os"
"strconv"
"strings"
-
- "github.com/prometheus/procfs/internal/util"
)
// A MountInfo is a type that describes the details, options
@@ -147,8 +147,7 @@ func mountOptionsParseOptionalFields(o []string) (map[string]string, error) {
// mountOptionsParser parses the mount options, superblock options.
func mountOptionsParser(mountOptions string) map[string]string {
opts := make(map[string]string)
- options := strings.Split(mountOptions, ",")
- for _, opt := range options {
+ for opt := range strings.SplitSeq(mountOptions, ",") {
splitOption := strings.Split(opt, "=")
if len(splitOption) < 2 {
key := splitOption[0]
@@ -161,9 +160,19 @@ func mountOptionsParser(mountOptions string) map[string]string {
return opts
}
+// readMountInfo reads a full mountinfo file (no 1 MiB cap, unlike util.ReadFileNoStat).
+func readMountInfo(path string) ([]byte, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return io.ReadAll(f)
+}
+
// GetMounts retrieves mountinfo information from `/proc/self/mountinfo`.
func GetMounts() ([]*MountInfo, error) {
- data, err := util.ReadFileNoStat("/proc/self/mountinfo")
+ data, err := readMountInfo("/proc/self/mountinfo")
if err != nil {
return nil, err
}
@@ -172,7 +181,25 @@ func GetMounts() ([]*MountInfo, error) {
// GetProcMounts retrieves mountinfo information from a processes' `/proc//mountinfo`.
func GetProcMounts(pid int) ([]*MountInfo, error) {
- data, err := util.ReadFileNoStat(fmt.Sprintf("/proc/%d/mountinfo", pid))
+ data, err := readMountInfo(fmt.Sprintf("/proc/%d/mountinfo", pid))
+ if err != nil {
+ return nil, err
+ }
+ return parseMountInfo(data)
+}
+
+// GetMounts retrieves mountinfo information from `/proc/self/mountinfo`.
+func (fs FS) GetMounts() ([]*MountInfo, error) {
+ data, err := readMountInfo(fs.proc.Path("self/mountinfo"))
+ if err != nil {
+ return nil, err
+ }
+ return parseMountInfo(data)
+}
+
+// GetProcMounts retrieves mountinfo information from a processes' `/proc//mountinfo`.
+func (fs FS) GetProcMounts(pid int) ([]*MountInfo, error) {
+ data, err := readMountInfo(fs.proc.Path(fmt.Sprintf("%d/mountinfo", pid)))
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go
index 50caa73274..e503cb3a6c 100644
--- a/vendor/github.com/prometheus/procfs/mountstats.go
+++ b/vendor/github.com/prometheus/procfs/mountstats.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -383,7 +383,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
if stats.Opts == nil {
stats.Opts = map[string]string{}
}
- for _, opt := range strings.Split(ss[1], ",") {
+ for opt := range strings.SplitSeq(ss[1], ",") {
split := strings.Split(opt, "=")
if len(split) == 2 {
stats.Opts[split[0]] = split[1]
diff --git a/vendor/github.com/prometheus/procfs/net_conntrackstat.go b/vendor/github.com/prometheus/procfs/net_conntrackstat.go
index 316df5fbb7..e9ca357079 100644
--- a/vendor/github.com/prometheus/procfs/net_conntrackstat.go
+++ b/vendor/github.com/prometheus/procfs/net_conntrackstat.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_dev.go b/vendor/github.com/prometheus/procfs/net_dev.go
index e66208aa05..7b3e1d61c9 100644
--- a/vendor/github.com/prometheus/procfs/net_dev.go
+++ b/vendor/github.com/prometheus/procfs/net_dev.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_dev_snmp6.go b/vendor/github.com/prometheus/procfs/net_dev_snmp6.go
index f50b38e352..2a0f60f29f 100644
--- a/vendor/github.com/prometheus/procfs/net_dev_snmp6.go
+++ b/vendor/github.com/prometheus/procfs/net_dev_snmp6.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -18,6 +18,7 @@ import (
"errors"
"io"
"os"
+ "path/filepath"
"strconv"
"strings"
)
@@ -56,7 +57,9 @@ func newNetDevSNMP6(dir string) (NetDevSNMP6, error) {
}
for _, iFaceFile := range ifaceFiles {
- f, err := os.Open(dir + "/" + iFaceFile.Name())
+ filePath := filepath.Join(dir, iFaceFile.Name())
+
+ f, err := os.Open(filePath)
if err != nil {
return netDevSNMP6, err
}
diff --git a/vendor/github.com/prometheus/procfs/net_ip_socket.go b/vendor/github.com/prometheus/procfs/net_ip_socket.go
index 19e3378f72..9291f8cd4c 100644
--- a/vendor/github.com/prometheus/procfs/net_ip_socket.go
+++ b/vendor/github.com/prometheus/procfs/net_ip_socket.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_protocols.go b/vendor/github.com/prometheus/procfs/net_protocols.go
index 8d4b1ac05b..eaa996cbcf 100644
--- a/vendor/github.com/prometheus/procfs/net_protocols.go
+++ b/vendor/github.com/prometheus/procfs/net_protocols.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -169,7 +169,7 @@ func (pc *NetProtocolCapabilities) parseCapabilities(capabilities []string) erro
&pc.EnterMemoryPressure,
}
- for i := 0; i < len(capabilities); i++ {
+ for i := range capabilities {
switch capabilities[i] {
case "y":
*capabilityFields[i] = true
diff --git a/vendor/github.com/prometheus/procfs/net_route.go b/vendor/github.com/prometheus/procfs/net_route.go
index deb7029fe1..fa3812d9d0 100644
--- a/vendor/github.com/prometheus/procfs/net_route.go
+++ b/vendor/github.com/prometheus/procfs/net_route.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_sockstat.go b/vendor/github.com/prometheus/procfs/net_sockstat.go
index fae62b13d9..8b221ebfff 100644
--- a/vendor/github.com/prometheus/procfs/net_sockstat.go
+++ b/vendor/github.com/prometheus/procfs/net_sockstat.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -139,9 +139,6 @@ func parseSockstatKVs(kvs []string) (map[string]int, error) {
func parseSockstatProtocol(kvs map[string]int) NetSockstatProtocol {
var nsp NetSockstatProtocol
for k, v := range kvs {
- // Capture the range variable to ensure we get unique pointers for
- // each of the optional fields.
- v := v
switch k {
case "inuse":
nsp.InUse = v
diff --git a/vendor/github.com/prometheus/procfs/net_softnet.go b/vendor/github.com/prometheus/procfs/net_softnet.go
index 71c8059f4d..4a2dfa18fd 100644
--- a/vendor/github.com/prometheus/procfs/net_softnet.go
+++ b/vendor/github.com/prometheus/procfs/net_softnet.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_tcp.go b/vendor/github.com/prometheus/procfs/net_tcp.go
index 0396d72015..2c7f9bc7c3 100644
--- a/vendor/github.com/prometheus/procfs/net_tcp.go
+++ b/vendor/github.com/prometheus/procfs/net_tcp.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -25,6 +25,7 @@ type (
// NetTCP returns the IPv4 kernel/networking statistics for TCP datagrams
// read from /proc/net/tcp.
+//
// Deprecated: Use github.com/mdlayher/netlink#Conn (with syscall.AF_INET) instead.
func (fs FS) NetTCP() (NetTCP, error) {
return newNetTCP(fs.proc.Path("net/tcp"))
@@ -32,6 +33,7 @@ func (fs FS) NetTCP() (NetTCP, error) {
// NetTCP6 returns the IPv6 kernel/networking statistics for TCP datagrams
// read from /proc/net/tcp6.
+//
// Deprecated: Use github.com/mdlayher/netlink#Conn (with syscall.AF_INET6) instead.
func (fs FS) NetTCP6() (NetTCP, error) {
return newNetTCP(fs.proc.Path("net/tcp6"))
@@ -39,6 +41,7 @@ func (fs FS) NetTCP6() (NetTCP, error) {
// NetTCPSummary returns already computed statistics like the total queue lengths
// for TCP datagrams read from /proc/net/tcp.
+//
// Deprecated: Use github.com/mdlayher/netlink#Conn (with syscall.AF_INET) instead.
func (fs FS) NetTCPSummary() (*NetTCPSummary, error) {
return newNetTCPSummary(fs.proc.Path("net/tcp"))
@@ -46,6 +49,7 @@ func (fs FS) NetTCPSummary() (*NetTCPSummary, error) {
// NetTCP6Summary returns already computed statistics like the total queue lengths
// for TCP datagrams read from /proc/net/tcp6.
+//
// Deprecated: Use github.com/mdlayher/netlink#Conn (with syscall.AF_INET6) instead.
func (fs FS) NetTCP6Summary() (*NetTCPSummary, error) {
return newNetTCPSummary(fs.proc.Path("net/tcp6"))
diff --git a/vendor/github.com/prometheus/procfs/net_tls_stat.go b/vendor/github.com/prometheus/procfs/net_tls_stat.go
index 13994c1782..b1b3f6a6a2 100644
--- a/vendor/github.com/prometheus/procfs/net_tls_stat.go
+++ b/vendor/github.com/prometheus/procfs/net_tls_stat.go
@@ -1,4 +1,4 @@
-// Copyright 2023 Prometheus Team
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_udp.go b/vendor/github.com/prometheus/procfs/net_udp.go
index 9ac3daf2d4..8a32779102 100644
--- a/vendor/github.com/prometheus/procfs/net_udp.go
+++ b/vendor/github.com/prometheus/procfs/net_udp.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_unix.go b/vendor/github.com/prometheus/procfs/net_unix.go
index d7e0cacb4c..e4d6359236 100644
--- a/vendor/github.com/prometheus/procfs/net_unix.go
+++ b/vendor/github.com/prometheus/procfs/net_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/net_wireless.go b/vendor/github.com/prometheus/procfs/net_wireless.go
index 7c597bc870..f74dd3bed0 100644
--- a/vendor/github.com/prometheus/procfs/net_wireless.go
+++ b/vendor/github.com/prometheus/procfs/net_wireless.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -114,47 +114,47 @@ func parseWireless(r io.Reader) ([]*Wireless, error) {
qlink, err := strconv.Atoi(strings.TrimSuffix(stats[1], "."))
if err != nil {
- return nil, fmt.Errorf("%w: parse Quality:link as integer %q: %w", ErrFileParse, qlink, err)
+ return nil, fmt.Errorf("%w: parse Quality:link as integer %q: %w", ErrFileParse, stats[1], err)
}
qlevel, err := strconv.Atoi(strings.TrimSuffix(stats[2], "."))
if err != nil {
- return nil, fmt.Errorf("%w: Quality:level as integer %q: %w", ErrFileParse, qlevel, err)
+ return nil, fmt.Errorf("%w: Quality:level as integer %q: %w", ErrFileParse, stats[2], err)
}
qnoise, err := strconv.Atoi(strings.TrimSuffix(stats[3], "."))
if err != nil {
- return nil, fmt.Errorf("%w: Quality:noise as integer %q: %w", ErrFileParse, qnoise, err)
+ return nil, fmt.Errorf("%w: Quality:noise as integer %q: %w", ErrFileParse, stats[3], err)
}
dnwid, err := strconv.Atoi(stats[4])
if err != nil {
- return nil, fmt.Errorf("%w: Discarded:nwid as integer %q: %w", ErrFileParse, dnwid, err)
+ return nil, fmt.Errorf("%w: Discarded:nwid as integer %q: %w", ErrFileParse, stats[4], err)
}
dcrypt, err := strconv.Atoi(stats[5])
if err != nil {
- return nil, fmt.Errorf("%w: Discarded:crypt as integer %q: %w", ErrFileParse, dcrypt, err)
+ return nil, fmt.Errorf("%w: Discarded:crypt as integer %q: %w", ErrFileParse, stats[5], err)
}
dfrag, err := strconv.Atoi(stats[6])
if err != nil {
- return nil, fmt.Errorf("%w: Discarded:frag as integer %q: %w", ErrFileParse, dfrag, err)
+ return nil, fmt.Errorf("%w: Discarded:frag as integer %q: %w", ErrFileParse, stats[6], err)
}
dretry, err := strconv.Atoi(stats[7])
if err != nil {
- return nil, fmt.Errorf("%w: Discarded:retry as integer %q: %w", ErrFileParse, dretry, err)
+ return nil, fmt.Errorf("%w: Discarded:retry as integer %q: %w", ErrFileParse, stats[7], err)
}
dmisc, err := strconv.Atoi(stats[8])
if err != nil {
- return nil, fmt.Errorf("%w: Discarded:misc as integer %q: %w", ErrFileParse, dmisc, err)
+ return nil, fmt.Errorf("%w: Discarded:misc as integer %q: %w", ErrFileParse, stats[8], err)
}
mbeacon, err := strconv.Atoi(stats[9])
if err != nil {
- return nil, fmt.Errorf("%w: Missed:beacon as integer %q: %w", ErrFileParse, mbeacon, err)
+ return nil, fmt.Errorf("%w: Missed:beacon as integer %q: %w", ErrFileParse, stats[9], err)
}
w := &Wireless{
diff --git a/vendor/github.com/prometheus/procfs/net_xfrm.go b/vendor/github.com/prometheus/procfs/net_xfrm.go
index 932ef20468..5a9f497d19 100644
--- a/vendor/github.com/prometheus/procfs/net_xfrm.go
+++ b/vendor/github.com/prometheus/procfs/net_xfrm.go
@@ -1,4 +1,4 @@
-// Copyright 2017 Prometheus Team
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/netstat.go b/vendor/github.com/prometheus/procfs/netstat.go
index 742dff453b..dbdae47392 100644
--- a/vendor/github.com/prometheus/procfs/netstat.go
+++ b/vendor/github.com/prometheus/procfs/netstat.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/nfnetlink_queue.go b/vendor/github.com/prometheus/procfs/nfnetlink_queue.go
new file mode 100644
index 0000000000..b0a73b11e9
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/nfnetlink_queue.go
@@ -0,0 +1,85 @@
+// Copyright The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+
+ "github.com/prometheus/procfs/internal/util"
+)
+
+const nfNetLinkQueueFormat = "%d %d %d %d %d %d %d %d %d"
+
+// NFNetLinkQueue contains general information about netfilter queues found in /proc/net/netfilter/nfnetlink_queue.
+type NFNetLinkQueue struct {
+ // id of the queue
+ QueueID uint
+ // pid of process handling the queue
+ PeerPID uint
+ // number of packets waiting for a decision
+ QueueTotal uint
+ // indicate how userspace receive packets
+ CopyMode uint
+ // size of copy
+ CopyRange uint
+ // number of items dropped by the kernel because too many packets were waiting a decision.
+ // It queue_total is superior to queue_max_len (1024 per default) the packets are dropped.
+ QueueDropped uint
+ // number of packets dropped by userspace (due to kernel send failure on the netlink socket)
+ QueueUserDropped uint
+ // sequence number of packets queued. It gives a correct approximation of the number of queued packets.
+ SequenceID uint
+ // internal value (number of entity using the queue)
+ Use uint
+}
+
+// NFNetLinkQueue returns information about current state of netfilter queues.
+func (fs FS) NFNetLinkQueue() ([]NFNetLinkQueue, error) {
+ data, err := util.ReadFileNoStat(fs.proc.Path("net/netfilter/nfnetlink_queue"))
+ if err != nil {
+ return nil, err
+ }
+
+ queue := []NFNetLinkQueue{}
+ if len(data) == 0 {
+ return queue, nil
+ }
+
+ scanner := bufio.NewScanner(bytes.NewReader(data))
+ for scanner.Scan() {
+ line := scanner.Text()
+ nFNetLinkQueue, err := parseNFNetLinkQueueLine(line)
+ if err != nil {
+ return nil, err
+ }
+ queue = append(queue, *nFNetLinkQueue)
+ }
+ return queue, nil
+}
+
+// parseNFNetLinkQueueLine parses each line of the /proc/net/netfilter/nfnetlink_queue file.
+func parseNFNetLinkQueueLine(line string) (*NFNetLinkQueue, error) {
+ nFNetLinkQueue := NFNetLinkQueue{}
+ _, err := fmt.Sscanf(
+ line, nfNetLinkQueueFormat,
+ &nFNetLinkQueue.QueueID, &nFNetLinkQueue.PeerPID, &nFNetLinkQueue.QueueTotal, &nFNetLinkQueue.CopyMode,
+ &nFNetLinkQueue.CopyRange, &nFNetLinkQueue.QueueDropped, &nFNetLinkQueue.QueueUserDropped, &nFNetLinkQueue.SequenceID, &nFNetLinkQueue.Use,
+ )
+ if err != nil {
+ return nil, err
+ }
+ return &nFNetLinkQueue, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go
index 368187fa88..39c14aa55e 100644
--- a/vendor/github.com/prometheus/procfs/proc.go
+++ b/vendor/github.com/prometheus/procfs/proc.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -49,7 +49,7 @@ func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }
// Self returns a process for the current process read via /proc/self.
func Self() (Proc, error) {
fs, err := NewFS(DefaultMountPoint)
- if err != nil || errors.Unwrap(err) == ErrMountPoint {
+ if err != nil || errors.Is(err, ErrMountPoint) {
return Proc{}, err
}
return fs.Self()
diff --git a/vendor/github.com/prometheus/procfs/proc_cgroup.go b/vendor/github.com/prometheus/procfs/proc_cgroup.go
index 4a64347c03..7e8a122978 100644
--- a/vendor/github.com/prometheus/procfs/proc_cgroup.go
+++ b/vendor/github.com/prometheus/procfs/proc_cgroup.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -60,7 +60,7 @@ func parseCgroupString(cgroupStr string) (*Cgroup, error) {
}
cgroup.HierarchyID, err = strconv.Atoi(fields[0])
if err != nil {
- return nil, fmt.Errorf("%w: hierarchy ID: %q", ErrFileParse, cgroup.HierarchyID)
+ return nil, fmt.Errorf("%w: hierarchy ID: %q", ErrFileParse, fields[0])
}
if fields[1] != "" {
ssNames := strings.Split(fields[1], ",")
diff --git a/vendor/github.com/prometheus/procfs/proc_cgroups.go b/vendor/github.com/prometheus/procfs/proc_cgroups.go
index 5dd4938999..0b275c3b1f 100644
--- a/vendor/github.com/prometheus/procfs/proc_cgroups.go
+++ b/vendor/github.com/prometheus/procfs/proc_cgroups.go
@@ -1,4 +1,4 @@
-// Copyright 2021 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -40,13 +40,13 @@ type CgroupSummary struct {
// parseCgroupSummary parses each line of the /proc/cgroup file
// Line format is `subsys_name hierarchy num_cgroups enabled`.
-func parseCgroupSummaryString(CgroupSummaryStr string) (*CgroupSummary, error) {
+func parseCgroupSummaryString(cgroupSummaryStr string) (*CgroupSummary, error) {
var err error
- fields := strings.Fields(CgroupSummaryStr)
+ fields := strings.Fields(cgroupSummaryStr)
// require at least 4 fields
if len(fields) < 4 {
- return nil, fmt.Errorf("%w: 4+ fields required, found %d fields in cgroup info string: %s", ErrFileParse, len(fields), CgroupSummaryStr)
+ return nil, fmt.Errorf("%w: 4+ fields required, found %d fields in cgroup info string: %s", ErrFileParse, len(fields), cgroupSummaryStr)
}
CgroupSummary := &CgroupSummary{
diff --git a/vendor/github.com/prometheus/procfs/proc_environ.go b/vendor/github.com/prometheus/procfs/proc_environ.go
index 57a89895d6..5b941de047 100644
--- a/vendor/github.com/prometheus/procfs/proc_environ.go
+++ b/vendor/github.com/prometheus/procfs/proc_environ.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/proc_fdinfo.go b/vendor/github.com/prometheus/procfs/proc_fdinfo.go
index fa761b3529..fa57761dbe 100644
--- a/vendor/github.com/prometheus/procfs/proc_fdinfo.go
+++ b/vendor/github.com/prometheus/procfs/proc_fdinfo.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -60,15 +60,16 @@ func (p Proc) FDInfo(fd string) (*ProcFDInfo, error) {
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
text = scanner.Text()
- if rPos.MatchString(text) {
+ switch {
+ case rPos.MatchString(text):
pos = rPos.FindStringSubmatch(text)[1]
- } else if rFlags.MatchString(text) {
+ case rFlags.MatchString(text):
flags = rFlags.FindStringSubmatch(text)[1]
- } else if rMntID.MatchString(text) {
+ case rMntID.MatchString(text):
mntid = rMntID.FindStringSubmatch(text)[1]
- } else if rIno.MatchString(text) {
+ case rIno.MatchString(text):
ino = rIno.FindStringSubmatch(text)[1]
- } else if rInotify.MatchString(text) {
+ case rInotify.MatchString(text):
newInotify, err := parseInotifyInfo(text)
if err != nil {
return nil, err
diff --git a/vendor/github.com/prometheus/procfs/proc_interrupts.go b/vendor/github.com/prometheus/procfs/proc_interrupts.go
index 86b4b45246..643b500d5d 100644
--- a/vendor/github.com/prometheus/procfs/proc_interrupts.go
+++ b/vendor/github.com/prometheus/procfs/proc_interrupts.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -42,7 +42,7 @@ type Interrupts map[string]Interrupt
// Interrupts creates a new instance from a given Proc instance.
func (p Proc) Interrupts() (Interrupts, error) {
- data, err := util.ReadFileNoStat(p.path("interrupts"))
+ data, err := util.ReadFileNoStat(p.fs.proc.Path("interrupts"))
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/prometheus/procfs/proc_io.go b/vendor/github.com/prometheus/procfs/proc_io.go
index d15b66ddb6..dd8086ba2e 100644
--- a/vendor/github.com/prometheus/procfs/proc_io.go
+++ b/vendor/github.com/prometheus/procfs/proc_io.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go
index 9530b14bc6..4b7d337847 100644
--- a/vendor/github.com/prometheus/procfs/proc_limits.go
+++ b/vendor/github.com/prometheus/procfs/proc_limits.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -19,6 +19,7 @@ import (
"os"
"regexp"
"strconv"
+ "strings"
)
// ProcLimits represents the soft limits for each of the process's resource
@@ -74,7 +75,7 @@ const (
)
var (
- limitsMatch = regexp.MustCompile(`(Max \w+\s{0,1}?\w*\s{0,1}\w*)\s{2,}(\w+)\s+(\w+)`)
+ limitsMatch = regexp.MustCompile(`(Max \w+\s??\w*\s?\w*)\s{2,}(\w+)\s+(\w+)`)
)
// NewLimits returns the current soft limits of the process.
@@ -106,7 +107,7 @@ func (p Proc) Limits() (ProcLimits, error) {
return ProcLimits{}, fmt.Errorf("%w: couldn't parse %q line %q", ErrFileParse, f.Name(), s.Text())
}
- switch fields[1] {
+ switch strings.TrimSpace(fields[1]) {
case "Max cpu time":
l.CPUTime, err = parseUint(fields[2])
case "Max file size":
diff --git a/vendor/github.com/prometheus/procfs/proc_maps.go b/vendor/github.com/prometheus/procfs/proc_maps.go
index 7e75c286b5..08b89a6eb9 100644
--- a/vendor/github.com/prometheus/procfs/proc_maps.go
+++ b/vendor/github.com/prometheus/procfs/proc_maps.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,8 +12,6 @@
// limitations under the License.
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) && !js
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
-// +build !js
package procfs
diff --git a/vendor/github.com/prometheus/procfs/proc_netstat.go b/vendor/github.com/prometheus/procfs/proc_netstat.go
index 4248c1716e..7f94cc8914 100644
--- a/vendor/github.com/prometheus/procfs/proc_netstat.go
+++ b/vendor/github.com/prometheus/procfs/proc_netstat.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/proc_ns.go b/vendor/github.com/prometheus/procfs/proc_ns.go
index 0f8f847f95..5fc0eb9e2f 100644
--- a/vendor/github.com/prometheus/procfs/proc_ns.go
+++ b/vendor/github.com/prometheus/procfs/proc_ns.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/proc_psi.go b/vendor/github.com/prometheus/procfs/proc_psi.go
index ccd35f153a..cc2c5de873 100644
--- a/vendor/github.com/prometheus/procfs/proc_psi.go
+++ b/vendor/github.com/prometheus/procfs/proc_psi.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/proc_smaps.go b/vendor/github.com/prometheus/procfs/proc_smaps.go
index 9a297afcf8..f637309b3d 100644
--- a/vendor/github.com/prometheus/procfs/proc_smaps.go
+++ b/vendor/github.com/prometheus/procfs/proc_smaps.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !windows
-// +build !windows
package procfs
diff --git a/vendor/github.com/prometheus/procfs/proc_snmp.go b/vendor/github.com/prometheus/procfs/proc_snmp.go
index 4bdc90b07e..8d9a9bcd67 100644
--- a/vendor/github.com/prometheus/procfs/proc_snmp.go
+++ b/vendor/github.com/prometheus/procfs/proc_snmp.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/proc_snmp6.go b/vendor/github.com/prometheus/procfs/proc_snmp6.go
index fb7fd3995b..841fef4649 100644
--- a/vendor/github.com/prometheus/procfs/proc_snmp6.go
+++ b/vendor/github.com/prometheus/procfs/proc_snmp6.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go
index 06a8d931c9..02e3f9e316 100644
--- a/vendor/github.com/prometheus/procfs/proc_stat.go
+++ b/vendor/github.com/prometheus/procfs/proc_stat.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -101,6 +101,12 @@ type ProcStat struct {
RSS int
// Soft limit in bytes on the rss of the process.
RSSLimit uint64
+ // The address above which program text can run.
+ StartCode uint64
+ // The address below which program text can run.
+ EndCode uint64
+ // The address of the start (i.e., bottom) of the stack.
+ StartStack uint64
// CPU number last executed on.
Processor uint
// Real-time scheduling priority, a number in the range 1 to 99 for processes
@@ -177,9 +183,9 @@ func (p Proc) Stat() (ProcStat, error) {
&s.VSize,
&s.RSS,
&s.RSSLimit,
- &ignoreUint64,
- &ignoreUint64,
- &ignoreUint64,
+ &s.StartCode,
+ &s.EndCode,
+ &s.StartStack,
&ignoreUint64,
&ignoreUint64,
&ignoreUint64,
diff --git a/vendor/github.com/prometheus/procfs/proc_statm.go b/vendor/github.com/prometheus/procfs/proc_statm.go
new file mode 100644
index 0000000000..6bcc97ec9c
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_statm.go
@@ -0,0 +1,117 @@
+// Copyright The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/prometheus/procfs/internal/util"
+)
+
+// - https://man7.org/linux/man-pages/man5/proc_pid_statm.5.html
+
+// ProcStatm Provides memory usage information for a process, measured in memory pages.
+// Read from /proc/[pid]/statm.
+type ProcStatm struct {
+ // The process ID.
+ PID int
+ // total program size (same as VmSize in status)
+ Size uint64
+ // resident set size (same as VmRSS in status)
+ Resident uint64
+ // number of resident shared pages (i.e., backed by a file)
+ Shared uint64
+ // text (code)
+ Text uint64
+ // library (unused since Linux 2.6; always 0)
+ Lib uint64
+ // data + stack
+ Data uint64
+ // dirty pages (unused since Linux 2.6; always 0)
+ Dt uint64
+}
+
+// NewStatm returns the current status information of the process.
+//
+// Deprecated: Use p.Statm() instead.
+func (p Proc) NewStatm() (ProcStatm, error) {
+ return p.Statm()
+}
+
+// Statm returns the current memory usage information of the process.
+func (p Proc) Statm() (ProcStatm, error) {
+ data, err := util.ReadFileNoStat(p.path("statm"))
+ if err != nil {
+ return ProcStatm{}, err
+ }
+
+ statmSlice, err := parseStatm(data)
+ if err != nil {
+ return ProcStatm{}, err
+ }
+
+ procStatm := ProcStatm{
+ PID: p.PID,
+ Size: statmSlice[0],
+ Resident: statmSlice[1],
+ Shared: statmSlice[2],
+ Text: statmSlice[3],
+ Lib: statmSlice[4],
+ Data: statmSlice[5],
+ Dt: statmSlice[6],
+ }
+
+ return procStatm, nil
+}
+
+// parseStatm return /proc/[pid]/statm data to uint64 slice.
+func parseStatm(data []byte) ([]uint64, error) {
+ var statmSlice []uint64
+ statmItems := strings.Fields(string(data))
+ for i := range statmItems {
+ statmItem, err := strconv.ParseUint(statmItems[i], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ statmSlice = append(statmSlice, statmItem)
+ }
+ return statmSlice, nil
+}
+
+// SizeBytes returns the process of total program size in bytes.
+func (s ProcStatm) SizeBytes() uint64 {
+ return s.Size * uint64(os.Getpagesize())
+}
+
+// ResidentBytes returns the process of resident set size in bytes.
+func (s ProcStatm) ResidentBytes() uint64 {
+ return s.Resident * uint64(os.Getpagesize())
+}
+
+// SHRBytes returns the process of share memory size in bytes.
+func (s ProcStatm) SHRBytes() uint64 {
+ return s.Shared * uint64(os.Getpagesize())
+}
+
+// TextBytes returns the process of text (code) size in bytes.
+func (s ProcStatm) TextBytes() uint64 {
+ return s.Text * uint64(os.Getpagesize())
+}
+
+// DataBytes returns the process of data + stack size in bytes.
+func (s ProcStatm) DataBytes() uint64 {
+ return s.Data * uint64(os.Getpagesize())
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_status.go b/vendor/github.com/prometheus/procfs/proc_status.go
index dd8aa56885..12d65581c8 100644
--- a/vendor/github.com/prometheus/procfs/proc_status.go
+++ b/vendor/github.com/prometheus/procfs/proc_status.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -16,7 +16,7 @@ package procfs
import (
"bytes"
"math/bits"
- "sort"
+ "slices"
"strconv"
"strings"
@@ -83,6 +83,19 @@ type ProcStatus struct {
// CpusAllowedList: List of cpu cores processes are allowed to run on.
CpusAllowedList []uint64
+
+ // CapInh is the bitmap of inheritable capabilities
+ //
+ // See: https://www.kernel.org/doc/man-pages/online/pages/man7/capabilities.7.html
+ CapInh uint64
+ // CapPrm is the bitmap of permitted capabilities
+ CapPrm uint64
+ // CapEff is the bitmap of effective capabilities
+ CapEff uint64
+ // CapBnd is the bitmap of bounding capabilities
+ CapBnd uint64
+ // CapAmb is the bitmap of ambient capabilities
+ CapAmb uint64
}
// NewStatus returns the current status information of the process.
@@ -94,8 +107,7 @@ func (p Proc) NewStatus() (ProcStatus, error) {
s := ProcStatus{PID: p.PID}
- lines := strings.Split(string(data), "\n")
- for _, line := range lines {
+ for line := range strings.SplitSeq(string(data), "\n") {
if !bytes.Contains([]byte(line), []byte(":")) {
continue
}
@@ -191,6 +203,36 @@ func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintByt
s.NonVoluntaryCtxtSwitches = vUint
case "Cpus_allowed_list":
s.CpusAllowedList = calcCpusAllowedList(vString)
+ case "CapInh":
+ var err error
+ s.CapInh, err = strconv.ParseUint(vString, 16, 64)
+ if err != nil {
+ return err
+ }
+ case "CapPrm":
+ var err error
+ s.CapPrm, err = strconv.ParseUint(vString, 16, 64)
+ if err != nil {
+ return err
+ }
+ case "CapEff":
+ var err error
+ s.CapEff, err = strconv.ParseUint(vString, 16, 64)
+ if err != nil {
+ return err
+ }
+ case "CapBnd":
+ var err error
+ s.CapBnd, err = strconv.ParseUint(vString, 16, 64)
+ if err != nil {
+ return err
+ }
+ case "CapAmb":
+ var err error
+ s.CapAmb, err = strconv.ParseUint(vString, 16, 64)
+ if err != nil {
+ return err
+ }
}
return nil
@@ -222,7 +264,7 @@ func calcCpusAllowedList(cpuString string) []uint64 {
}
- sort.Slice(g, func(i, j int) bool { return g[i] < g[j] })
+ slices.Sort(g)
return g
}
diff --git a/vendor/github.com/prometheus/procfs/proc_sys.go b/vendor/github.com/prometheus/procfs/proc_sys.go
index 3810d1ac99..52658a4d52 100644
--- a/vendor/github.com/prometheus/procfs/proc_sys.go
+++ b/vendor/github.com/prometheus/procfs/proc_sys.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/schedstat.go b/vendor/github.com/prometheus/procfs/schedstat.go
index 5f7f32dc83..fafd8dff74 100644
--- a/vendor/github.com/prometheus/procfs/schedstat.go
+++ b/vendor/github.com/prometheus/procfs/schedstat.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/slab.go b/vendor/github.com/prometheus/procfs/slab.go
index 8611c90177..32a04678ad 100644
--- a/vendor/github.com/prometheus/procfs/slab.go
+++ b/vendor/github.com/prometheus/procfs/slab.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/softirqs.go b/vendor/github.com/prometheus/procfs/softirqs.go
index 403e6ae708..47b73a7297 100644
--- a/vendor/github.com/prometheus/procfs/softirqs.go
+++ b/vendor/github.com/prometheus/procfs/softirqs.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go
index e36b41c18a..593ad0f62f 100644
--- a/vendor/github.com/prometheus/procfs/stat.go
+++ b/vendor/github.com/prometheus/procfs/stat.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -16,6 +16,7 @@ package procfs
import (
"bufio"
"bytes"
+ "errors"
"fmt"
"io"
"strconv"
@@ -92,7 +93,7 @@ func parseCPUStat(line string) (CPUStat, int64, error) {
&cpuStat.Iowait, &cpuStat.IRQ, &cpuStat.SoftIRQ, &cpuStat.Steal,
&cpuStat.Guest, &cpuStat.GuestNice)
- if err != nil && err != io.EOF {
+ if err != nil && !errors.Is(err, io.EOF) {
return CPUStat{}, -1, fmt.Errorf("%w: couldn't parse %q (cpu): %w", ErrFileParse, line, err)
}
if count == 0 {
diff --git a/vendor/github.com/prometheus/procfs/swaps.go b/vendor/github.com/prometheus/procfs/swaps.go
index 65fec834bf..ee17bf4888 100644
--- a/vendor/github.com/prometheus/procfs/swaps.go
+++ b/vendor/github.com/prometheus/procfs/swaps.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/thread.go b/vendor/github.com/prometheus/procfs/thread.go
index 80e0e947be..0cfbb54184 100644
--- a/vendor/github.com/prometheus/procfs/thread.go
+++ b/vendor/github.com/prometheus/procfs/thread.go
@@ -1,4 +1,4 @@
-// Copyright 2022 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
diff --git a/vendor/github.com/prometheus/procfs/vm.go b/vendor/github.com/prometheus/procfs/vm.go
index 51c49d89e8..52180c03e2 100644
--- a/vendor/github.com/prometheus/procfs/vm.go
+++ b/vendor/github.com/prometheus/procfs/vm.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !windows
-// +build !windows
package procfs
diff --git a/vendor/github.com/prometheus/procfs/zoneinfo.go b/vendor/github.com/prometheus/procfs/zoneinfo.go
index e54d94b090..63d1898bc8 100644
--- a/vendor/github.com/prometheus/procfs/zoneinfo.go
+++ b/vendor/github.com/prometheus/procfs/zoneinfo.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Prometheus Authors
+// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -12,7 +12,6 @@
// limitations under the License.
//go:build !windows
-// +build !windows
package procfs
@@ -88,11 +87,9 @@ func parseZoneinfo(zoneinfoData []byte) ([]Zoneinfo, error) {
zoneinfo := []Zoneinfo{}
- zoneinfoBlocks := bytes.Split(zoneinfoData, []byte("\nNode"))
- for _, block := range zoneinfoBlocks {
+ for block := range bytes.SplitSeq(zoneinfoData, []byte("\nNode")) {
var zoneinfoElement Zoneinfo
- lines := strings.Split(string(block), "\n")
- for _, line := range lines {
+ for line := range strings.SplitSeq(string(block), "\n") {
if nodeZone := nodeZoneRE.FindStringSubmatch(line); nodeZone != nil {
zoneinfoElement.Node = nodeZone[1]
diff --git a/vendor/github.com/sirupsen/logrus/.golangci.yml b/vendor/github.com/sirupsen/logrus/.golangci.yml
index 65dc285037..792db36181 100644
--- a/vendor/github.com/sirupsen/logrus/.golangci.yml
+++ b/vendor/github.com/sirupsen/logrus/.golangci.yml
@@ -1,40 +1,67 @@
+version: "2"
run:
- # do not run on test files yet
tests: false
-
-# all available settings of specific linters
-linters-settings:
- errcheck:
- # report about not checking of errors in type assetions: `a := b.(MyStruct)`;
- # default is false: such cases aren't reported by default.
- check-type-assertions: false
-
- # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
- # default is false: such cases aren't reported by default.
- check-blank: false
-
- lll:
- line-length: 100
- tab-width: 4
-
- prealloc:
- simple: false
- range-loops: false
- for-loops: false
-
- whitespace:
- multi-if: false # Enforces newlines (or comments) after every multi-line if statement
- multi-func: false # Enforces newlines (or comments) after every multi-line function signature
-
linters:
enable:
- - megacheck
- - govet
+ - asasalint
+ - asciicheck
+ - bidichk
+ - bodyclose
+ - contextcheck
+ - durationcheck
+ - errchkjson
+ - errorlint
+ - exhaustive
+ - gocheckcompilerdirectives
+ - gochecksumtype
+ - gosec
+ - gosmopolitan
+ - loggercheck
+ - makezero
+ - musttag
+ - nilerr
+ - nilnesserr
+ - noctx
+ - protogetter
+ - reassign
+ - recvcheck
+ - rowserrcheck
+ - spancheck
+ - sqlclosecheck
+ - testifylint
+ - unparam
+ - zerologlint
disable:
- - maligned
- prealloc
- disable-all: false
- presets:
- - bugs
- - unused
- fast: false
+ settings:
+ errcheck:
+ check-type-assertions: false
+ check-blank: false
+ lll:
+ line-length: 100
+ tab-width: 4
+ prealloc:
+ simple: false
+ range-loops: false
+ for-loops: false
+ whitespace:
+ multi-if: false
+ multi-func: false
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
+formatters:
+ exclusions:
+ generated: lax
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md
index 7567f61289..098608ff4b 100644
--- a/vendor/github.com/sirupsen/logrus/CHANGELOG.md
+++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md
@@ -37,7 +37,7 @@ Features:
# 1.6.0
Fixes:
* end of line cleanup
- * revert the entry concurrency bug fix whic leads to deadlock under some circumstances
+ * revert the entry concurrency bug fix which leads to deadlock under some circumstances
* update dependency on go-windows-terminal-sequences to fix a crash with go 1.14
Features:
@@ -129,7 +129,7 @@ This new release introduces:
which is mostly useful for logger wrapper
* a fix reverting the immutability of the entry given as parameter to the hooks
a new configuration field of the json formatter in order to put all the fields
- in a nested dictionnary
+ in a nested dictionary
* a new SetOutput method in the Logger
* a new configuration of the textformatter to configure the name of the default keys
* a new configuration of the text formatter to disable the level truncation
diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md
index d1d4a85fd7..cc5dab7eb7 100644
--- a/vendor/github.com/sirupsen/logrus/README.md
+++ b/vendor/github.com/sirupsen/logrus/README.md
@@ -1,4 +1,4 @@
-# Logrus
[](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [](https://travis-ci.org/sirupsen/logrus) [](https://pkg.go.dev/github.com/sirupsen/logrus)
+# Logrus
[](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [](https://pkg.go.dev/github.com/sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger.
@@ -40,7 +40,7 @@ plain text):

-With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
+With `logrus.SetFormatter(&logrus.JSONFormatter{})`, for easy parsing by logstash
or Splunk:
```text
@@ -60,9 +60,9 @@ ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
```
-With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
+With the default `logrus.SetFormatter(&logrus.TextFormatter{})` when a TTY is not
attached, the output is compatible with the
-[logfmt](http://godoc.org/github.com/kr/logfmt) format:
+[logfmt](https://pkg.go.dev/github.com/kr/logfmt) format:
```text
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
@@ -75,17 +75,18 @@ time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x20822
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
```go
- log.SetFormatter(&log.TextFormatter{
- DisableColors: true,
- FullTimestamp: true,
- })
+logrus.SetFormatter(&logrus.TextFormatter{
+ DisableColors: true,
+ FullTimestamp: true,
+})
```
#### Logging Method Name
If you wish to add the calling method as a field, instruct the logger via:
+
```go
-log.SetReportCaller(true)
+logrus.SetReportCaller(true)
```
This adds the caller as 'method' like so:
@@ -100,11 +101,11 @@ time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcr
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
environment via benchmarks:
-```
+
+```bash
go test -bench=.*CallerTracing
```
-
#### Case-sensitivity
The organization's name was changed to lower-case--and this will not be changed
@@ -118,12 +119,10 @@ The simplest way to use Logrus is simply the package-level exported logger:
```go
package main
-import (
- log "github.com/sirupsen/logrus"
-)
+import "github.com/sirupsen/logrus"
func main() {
- log.WithFields(log.Fields{
+ logrus.WithFields(logrus.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}
@@ -139,6 +138,7 @@ package main
import (
"os"
+
log "github.com/sirupsen/logrus"
)
@@ -190,26 +190,27 @@ package main
import (
"os"
+
"github.com/sirupsen/logrus"
)
// Create a new instance of the logger. You can have any number of instances.
-var log = logrus.New()
+var logger = logrus.New()
func main() {
// The API for setting attributes is a little different than the package level
- // exported logger. See Godoc.
- log.Out = os.Stdout
+ // exported logger. See Godoc.
+ logger.Out = os.Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
// if err == nil {
- // log.Out = file
+ // logger.Out = file
// } else {
- // log.Info("Failed to log to file, using default stderr")
+ // logger.Info("Failed to log to file, using default stderr")
// }
- log.WithFields(logrus.Fields{
+ logger.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
@@ -219,12 +220,12 @@ func main() {
#### Fields
Logrus encourages careful, structured logging through logging fields instead of
-long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
+long, unparseable error messages. For example, instead of: `logrus.Fatalf("Failed
to send event %s to topic %s with key %d")`, you should log the much more
discoverable:
```go
-log.WithFields(log.Fields{
+logrus.WithFields(logrus.Fields{
"event": event,
"topic": topic,
"key": key,
@@ -245,12 +246,12 @@ seen as a hint you should add a field, however, you can still use the
Often it's helpful to have fields _always_ attached to log statements in an
application or parts of one. For example, you may want to always log the
`request_id` and `user_ip` in the context of a request. Instead of writing
-`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
+`logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip})` on
every line, you can create a `logrus.Entry` to pass around instead:
```go
-requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
-requestLogger.Info("something happened on that request") # will log request_id and user_ip
+requestLogger := logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip})
+requestLogger.Info("something happened on that request") // will log request_id and user_ip
requestLogger.Warn("something not great happened")
```
@@ -264,28 +265,31 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
`init`:
```go
+package main
+
import (
- log "github.com/sirupsen/logrus"
- "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
- logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
"log/syslog"
+
+ "github.com/sirupsen/logrus"
+ airbrake "gopkg.in/gemnasium/logrus-airbrake-hook.v2"
+ logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
)
func init() {
// Use the Airbrake hook to report errors that have Error severity or above to
// an exception tracker. You can create custom hooks, see the Hooks section.
- log.AddHook(airbrake.NewHook(123, "xyz", "production"))
+ logrus.AddHook(airbrake.NewHook(123, "xyz", "production"))
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err != nil {
- log.Error("Unable to connect to local syslog daemon")
+ logrus.Error("Unable to connect to local syslog daemon")
} else {
- log.AddHook(hook)
+ logrus.AddHook(hook)
}
}
```
-Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
+Note: Syslog hooks also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
@@ -295,15 +299,15 @@ A list of currently known service hooks can be found in this wiki [page](https:/
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
```go
-log.Trace("Something very low level.")
-log.Debug("Useful debugging information.")
-log.Info("Something noteworthy happened!")
-log.Warn("You should probably take a look at this.")
-log.Error("Something failed but I'm not quitting.")
+logrus.Trace("Something very low level.")
+logrus.Debug("Useful debugging information.")
+logrus.Info("Something noteworthy happened!")
+logrus.Warn("You should probably take a look at this.")
+logrus.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
-log.Fatal("Bye.")
+logrus.Fatal("Bye.")
// Calls panic() after logging
-log.Panic("I'm bailing.")
+logrus.Panic("I'm bailing.")
```
You can set the logging level on a `Logger`, then it will only log entries with
@@ -311,13 +315,13 @@ that severity or anything above it:
```go
// Will log anything that is info or above (warn, error, fatal, panic). Default.
-log.SetLevel(log.InfoLevel)
+logrus.SetLevel(logrus.InfoLevel)
```
-It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
+It may be useful to set `logrus.Level = logrus.DebugLevel` in a debug or verbose
environment if your application has that.
-Note: If you want different log levels for global (`log.SetLevel(...)`) and syslog logging, please check the [syslog hook README](hooks/syslog/README.md#different-log-levels-for-local-and-remote-logging).
+Note: If you want different log levels for global (`logrus.SetLevel(...)`) and syslog logging, please check the [syslog hook README](hooks/syslog/README.md#different-log-levels-for-local-and-remote-logging).
#### Entries
@@ -340,17 +344,17 @@ could do:
```go
import (
- log "github.com/sirupsen/logrus"
+ "github.com/sirupsen/logrus"
)
func init() {
// do something here to set environment depending on an environment variable
// or command-line flag
if Environment == "production" {
- log.SetFormatter(&log.JSONFormatter{})
+ logrus.SetFormatter(&logrus.JSONFormatter{})
} else {
// The TextFormatter is default, you don't actually have to do this.
- log.SetFormatter(&log.TextFormatter{})
+ logrus.SetFormatter(&logrus.TextFormatter{})
}
}
```
@@ -372,11 +376,11 @@ The built-in logging formatters are:
* When colors are enabled, levels are truncated to 4 characters by default. To disable
truncation set the `DisableLevelTruncation` field to `true`.
* When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
- * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
+ * All options are listed in the [generated docs](https://pkg.go.dev/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON.
- * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
+ * All options are listed in the [generated docs](https://pkg.go.dev/github.com/sirupsen/logrus#JSONFormatter).
-Third party logging formatters:
+Third-party logging formatters:
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
@@ -384,7 +388,7 @@ Third party logging formatters:
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo.
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
-* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Sava log to files.
+* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Save log to files.
* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added.
You can define your formatter by implementing the `Formatter` interface,
@@ -393,10 +397,9 @@ requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
default ones (see Entries section above):
```go
-type MyJSONFormatter struct {
-}
+type MyJSONFormatter struct{}
-log.SetFormatter(new(MyJSONFormatter))
+logrus.SetFormatter(new(MyJSONFormatter))
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
// Note this doesn't include Time, Level and Message which are available on
@@ -455,17 +458,18 @@ entries. It should not be a feature of the application-level logger.
#### Testing
-Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
+Logrus has a built-in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
```go
import(
+ "testing"
+
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
- "testing"
)
func TestSomething(t*testing.T){
@@ -486,15 +490,15 @@ func TestSomething(t*testing.T){
Logrus can register one or more functions that will be called when any `fatal`
level message is logged. The registered handlers will be executed before
logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need
-to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
+to gracefully shut down. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
-```
-...
+```go
+// ...
handler := func() {
- // gracefully shutdown something...
+ // gracefully shut down something...
}
logrus.RegisterExitHandler(handler)
-...
+// ...
```
#### Thread safety
@@ -502,7 +506,7 @@ logrus.RegisterExitHandler(handler)
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
-Situation when locking is not needed includes:
+Situations when locking is not needed include:
* You have no hooks registered, or hooks calling is already thread-safe.
diff --git a/vendor/github.com/sirupsen/logrus/appveyor.yml b/vendor/github.com/sirupsen/logrus/appveyor.yml
index df9d65c3a5..e90f09ea68 100644
--- a/vendor/github.com/sirupsen/logrus/appveyor.yml
+++ b/vendor/github.com/sirupsen/logrus/appveyor.yml
@@ -1,14 +1,12 @@
-version: "{build}"
+# Minimal stub to satisfy AppVeyor CI
+version: 1.0.{build}
platform: x64
-clone_folder: c:\gopath\src\github.com\sirupsen\logrus
-environment:
- GOPATH: c:\gopath
+shallow_clone: true
+
branches:
only:
- master
-install:
- - set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- - go version
+ - main
+
build_script:
- - go get -t
- - go test
+ - echo "No-op build to satisfy AppVeyor CI"
diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go
index 71cdbbc35d..71d796d0b1 100644
--- a/vendor/github.com/sirupsen/logrus/entry.go
+++ b/vendor/github.com/sirupsen/logrus/entry.go
@@ -34,13 +34,15 @@ func init() {
minimumCallerDepth = 1
}
-// Defines the key when adding errors using WithError.
+// ErrorKey defines the key when adding errors using [WithError], [Logger.WithError].
var ErrorKey = "error"
-// An entry is the final or intermediate Logrus logging entry. It contains all
+// Entry is the final or intermediate Logrus logging entry. It contains all
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
// reused and passed around as much as you wish to avoid field duplication.
+//
+//nolint:recvcheck // the methods of "Entry" use pointer receiver and non-pointer receiver.
type Entry struct {
Logger *Logger
@@ -86,12 +88,12 @@ func (entry *Entry) Dup() *Entry {
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, Context: entry.Context, err: entry.err}
}
-// Returns the bytes representation of this entry from the formatter.
+// Bytes returns the bytes representation of this entry from the formatter.
func (entry *Entry) Bytes() ([]byte, error) {
return entry.Logger.Formatter.Format(entry)
}
-// Returns the string representation from the reader and ultimately the
+// String returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
serialized, err := entry.Bytes()
@@ -102,12 +104,13 @@ func (entry *Entry) String() (string, error) {
return str, nil
}
-// Add an error as single field (using the key defined in ErrorKey) to the Entry.
+// WithError adds an error as single field (using the key defined in [ErrorKey])
+// to the Entry.
func (entry *Entry) WithError(err error) *Entry {
return entry.WithField(ErrorKey, err)
}
-// Add a context to the Entry.
+// WithContext adds a context to the Entry.
func (entry *Entry) WithContext(ctx context.Context) *Entry {
dataCopy := make(Fields, len(entry.Data))
for k, v := range entry.Data {
@@ -116,12 +119,12 @@ func (entry *Entry) WithContext(ctx context.Context) *Entry {
return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
}
-// Add a single field to the Entry.
+// WithField adds a single field to the Entry.
func (entry *Entry) WithField(key string, value interface{}) *Entry {
return entry.WithFields(Fields{key: value})
}
-// Add a map of fields to the Entry.
+// WithFields adds a map of fields to the Entry.
func (entry *Entry) WithFields(fields Fields) *Entry {
data := make(Fields, len(entry.Data)+len(fields))
for k, v := range entry.Data {
@@ -150,7 +153,7 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
}
-// Overrides the time of the Entry.
+// WithTime overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
dataCopy := make(Fields, len(entry.Data))
for k, v := range entry.Data {
@@ -204,7 +207,7 @@ func getCaller() *runtime.Frame {
// If the caller isn't part of this package, we're done
if pkg != logrusPackage {
- return &f //nolint:scopelint
+ return &f
}
}
@@ -432,7 +435,7 @@ func (entry *Entry) Panicln(args ...interface{}) {
entry.Logln(PanicLevel, args...)
}
-// Sprintlnn => Sprint no newline. This is to get the behavior of how
+// sprintlnn => Sprint no newline. This is to get the behavior of how
// fmt.Sprintln where spaces are always added between operands, regardless of
// their type. Instead of vendoring the Sprintln implementation to spare a
// string allocation, we do the simplest thing.
diff --git a/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go
index 3f151cdc39..9ab978a457 100644
--- a/vendor/github.com/sirupsen/logrus/hooks.go
+++ b/vendor/github.com/sirupsen/logrus/hooks.go
@@ -1,16 +1,16 @@
package logrus
-// A hook to be fired when logging on the logging levels returned from
-// `Levels()` on your implementation of the interface. Note that this is not
+// Hook describes hooks to be fired when logging on the logging levels returned from
+// [Hook.Levels] on your implementation of the interface. Note that this is not
// fired in a goroutine or a channel with workers, you should handle such
-// functionality yourself if your call is non-blocking and you don't wish for
+// functionality yourself if your call is non-blocking, and you don't wish for
// the logging calls for levels returned from `Levels()` to block.
type Hook interface {
Levels() []Level
Fire(*Entry) error
}
-// Internal type for storing the hooks on a logger instance.
+// LevelHooks is an internal type for storing the hooks on a logger instance.
type LevelHooks map[Level][]Hook
// Add a hook to an instance of logger. This is called with
diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go
index 5ff0aef6d3..f5b8c439ee 100644
--- a/vendor/github.com/sirupsen/logrus/logger.go
+++ b/vendor/github.com/sirupsen/logrus/logger.go
@@ -72,16 +72,16 @@ func (mw *MutexWrap) Disable() {
mw.disabled = true
}
-// Creates a new logger. Configuration should be set by changing `Formatter`,
-// `Out` and `Hooks` directly on the default logger instance. You can also just
+// New Creates a new logger. Configuration should be set by changing [Formatter],
+// Out and Hooks directly on the default Logger instance. You can also just
// instantiate your own:
//
-// var log = &logrus.Logger{
-// Out: os.Stderr,
-// Formatter: new(logrus.TextFormatter),
-// Hooks: make(logrus.LevelHooks),
-// Level: logrus.DebugLevel,
-// }
+// var log = &logrus.Logger{
+// Out: os.Stderr,
+// Formatter: new(logrus.TextFormatter),
+// Hooks: make(logrus.LevelHooks),
+// Level: logrus.DebugLevel,
+// }
//
// It's recommended to make this a global instance called `log`.
func New() *Logger {
@@ -118,30 +118,30 @@ func (logger *Logger) WithField(key string, value interface{}) *Entry {
return entry.WithField(key, value)
}
-// Adds a struct of fields to the log entry. All it does is call `WithField` for
-// each `Field`.
+// WithFields adds a struct of fields to the log entry. It calls [Entry.WithField]
+// for each Field.
func (logger *Logger) WithFields(fields Fields) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithFields(fields)
}
-// Add an error as single field to the log entry. All it does is call
-// `WithError` for the given `error`.
+// WithError adds an error as single field to the log entry. It calls
+// [Entry.WithError] for the given error.
func (logger *Logger) WithError(err error) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithError(err)
}
-// Add a context to the log entry.
+// WithContext add a context to the log entry.
func (logger *Logger) WithContext(ctx context.Context) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithContext(ctx)
}
-// Overrides the time of the log entry.
+// WithTime overrides the time of the log entry.
func (logger *Logger) WithTime(t time.Time) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
@@ -347,9 +347,9 @@ func (logger *Logger) Exit(code int) {
logger.ExitFunc(code)
}
-//When file is opened with appending mode, it's safe to
-//write concurrently to a file (within 4k message on Linux).
-//In these cases user can choose to disable the lock.
+// SetNoLock disables the lock for situations where a file is opened with
+// appending mode, and safe for concurrent writes to the file (within 4k
+// message on Linux). In these cases user can choose to disable the lock.
func (logger *Logger) SetNoLock() {
logger.mu.Disable()
}
diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go
index 2f16224cb9..37fc4fef85 100644
--- a/vendor/github.com/sirupsen/logrus/logrus.go
+++ b/vendor/github.com/sirupsen/logrus/logrus.go
@@ -6,13 +6,15 @@ import (
"strings"
)
-// Fields type, used to pass to `WithFields`.
+// Fields type, used to pass to [WithFields].
type Fields map[string]interface{}
// Level type
+//
+//nolint:recvcheck // the methods of "Entry" use pointer receiver and non-pointer receiver.
type Level uint32
-// Convert the Level to a string. E.g. PanicLevel becomes "panic".
+// Convert the Level to a string. E.g. [PanicLevel] becomes "panic".
func (level Level) String() string {
if b, err := level.MarshalText(); err == nil {
return string(b)
@@ -77,7 +79,7 @@ func (level Level) MarshalText() ([]byte, error) {
return nil, fmt.Errorf("not a valid logrus level %d", level)
}
-// A constant exposing all logging levels
+// AllLevels exposing all logging levels.
var AllLevels = []Level{
PanicLevel,
FatalLevel,
@@ -119,8 +121,8 @@ var (
)
// StdLogger is what your logrus-enabled library should take, that way
-// it'll accept a stdlib logger and a logrus logger. There's no standard
-// interface, this is the closest we get, unfortunately.
+// it'll accept a stdlib logger ([log.Logger]) and a logrus logger.
+// There's no standard interface, so this is the closest we get, unfortunately.
type StdLogger interface {
Print(...interface{})
Printf(string, ...interface{})
@@ -135,7 +137,8 @@ type StdLogger interface {
Panicln(...interface{})
}
-// The FieldLogger interface generalizes the Entry and Logger types
+// FieldLogger extends the [StdLogger] interface, generalizing
+// the [Entry] and [Logger] types.
type FieldLogger interface {
WithField(key string, value interface{}) *Entry
WithFields(fields Fields) *Entry
@@ -176,8 +179,9 @@ type FieldLogger interface {
// IsPanicEnabled() bool
}
-// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
-// here for consistancy. Do not use. Use Logger or Entry instead.
+// Ext1FieldLogger (the first extension to [FieldLogger]) is superfluous, it is
+// here for consistency. Do not use. Use [FieldLogger], [Logger] or [Entry]
+// instead.
type Ext1FieldLogger interface {
FieldLogger
Tracef(format string, args ...interface{})
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
index 499789984d..69956b425a 100644
--- a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
@@ -1,4 +1,4 @@
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd netbsd openbsd hurd
// +build !js
package logrus
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
index 04748b8515..c9aed267a4 100644
--- a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
@@ -1,5 +1,7 @@
+//go:build (linux || aix || zos) && !js && !wasi
// +build linux aix zos
// +build !js
+// +build !wasi
package logrus
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go b/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go
new file mode 100644
index 0000000000..2822b212fb
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go
@@ -0,0 +1,8 @@
+//go:build wasi
+// +build wasi
+
+package logrus
+
+func isTerminal(fd int) bool {
+ return false
+}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go b/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go
new file mode 100644
index 0000000000..108a6be12b
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go
@@ -0,0 +1,8 @@
+//go:build wasip1
+// +build wasip1
+
+package logrus
+
+func isTerminal(fd int) bool {
+ return false
+}
diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go
index be2c6efe5e..6dfeb18b10 100644
--- a/vendor/github.com/sirupsen/logrus/text_formatter.go
+++ b/vendor/github.com/sirupsen/logrus/text_formatter.go
@@ -306,6 +306,7 @@ func (f *TextFormatter) needsQuoting(text string) bool {
return false
}
for _, ch := range text {
+ //nolint:staticcheck // QF1001: could apply De Morgan's law
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
@@ -334,6 +335,6 @@ func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
if !f.needsQuoting(stringVal) {
b.WriteString(stringVal)
} else {
- b.WriteString(fmt.Sprintf("%q", stringVal))
+ fmt.Fprintf(b, "%q", stringVal)
}
}
diff --git a/vendor/go.yaml.in/yaml/v2/.travis.yml b/vendor/go.yaml.in/yaml/v2/.travis.yml
deleted file mode 100644
index 7348c50c0c..0000000000
--- a/vendor/go.yaml.in/yaml/v2/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: go
-
-go:
- - "1.4.x"
- - "1.5.x"
- - "1.6.x"
- - "1.7.x"
- - "1.8.x"
- - "1.9.x"
- - "1.10.x"
- - "1.11.x"
- - "1.12.x"
- - "1.13.x"
- - "1.14.x"
- - "tip"
-
-go_import_path: gopkg.in/yaml.v2
diff --git a/vendor/go.yaml.in/yaml/v2/LICENSE b/vendor/go.yaml.in/yaml/v2/LICENSE
deleted file mode 100644
index 8dada3edaf..0000000000
--- a/vendor/go.yaml.in/yaml/v2/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/go.yaml.in/yaml/v2/LICENSE.libyaml b/vendor/go.yaml.in/yaml/v2/LICENSE.libyaml
deleted file mode 100644
index 8da58fbf6f..0000000000
--- a/vendor/go.yaml.in/yaml/v2/LICENSE.libyaml
+++ /dev/null
@@ -1,31 +0,0 @@
-The following files were ported to Go from C files of libyaml, and thus
-are still covered by their original copyright and license:
-
- apic.go
- emitterc.go
- parserc.go
- readerc.go
- scannerc.go
- writerc.go
- yamlh.go
- yamlprivateh.go
-
-Copyright (c) 2006 Kirill Simonov
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/vendor/go.yaml.in/yaml/v2/NOTICE b/vendor/go.yaml.in/yaml/v2/NOTICE
deleted file mode 100644
index 866d74a7ad..0000000000
--- a/vendor/go.yaml.in/yaml/v2/NOTICE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2011-2016 Canonical Ltd.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/vendor/go.yaml.in/yaml/v2/README.md b/vendor/go.yaml.in/yaml/v2/README.md
deleted file mode 100644
index c9388da425..0000000000
--- a/vendor/go.yaml.in/yaml/v2/README.md
+++ /dev/null
@@ -1,131 +0,0 @@
-# YAML support for the Go language
-
-Introduction
-------------
-
-The yaml package enables Go programs to comfortably encode and decode YAML
-values. It was developed within [Canonical](https://www.canonical.com) as
-part of the [juju](https://juju.ubuntu.com) project, and is based on a
-pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
-C library to parse and generate YAML data quickly and reliably.
-
-Compatibility
--------------
-
-The yaml package supports most of YAML 1.1 and 1.2, including support for
-anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
-implemented, and base-60 floats from YAML 1.1 are purposefully not
-supported since they're a poor design and are gone in YAML 1.2.
-
-Installation and usage
-----------------------
-
-The import path for the package is *go.yaml.in/yaml/v2*.
-
-To install it, run:
-
- go get go.yaml.in/yaml/v2
-
-API documentation
------------------
-
-See:
-
-API stability
--------------
-
-The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in).
-
-
-License
--------
-
-The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details.
-
-
-Example
--------
-
-```Go
-package main
-
-import (
- "fmt"
- "log"
-
- "go.yaml.in/yaml/v2"
-)
-
-var data = `
-a: Easy!
-b:
- c: 2
- d: [3, 4]
-`
-
-// Note: struct fields must be public in order for unmarshal to
-// correctly populate the data.
-type T struct {
- A string
- B struct {
- RenamedC int `yaml:"c"`
- D []int `yaml:",flow"`
- }
-}
-
-func main() {
- t := T{}
-
- err := yaml.Unmarshal([]byte(data), &t)
- if err != nil {
- log.Fatalf("error: %v", err)
- }
- fmt.Printf("--- t:\n%v\n\n", t)
-
- d, err := yaml.Marshal(&t)
- if err != nil {
- log.Fatalf("error: %v", err)
- }
- fmt.Printf("--- t dump:\n%s\n\n", string(d))
-
- m := make(map[interface{}]interface{})
-
- err = yaml.Unmarshal([]byte(data), &m)
- if err != nil {
- log.Fatalf("error: %v", err)
- }
- fmt.Printf("--- m:\n%v\n\n", m)
-
- d, err = yaml.Marshal(&m)
- if err != nil {
- log.Fatalf("error: %v", err)
- }
- fmt.Printf("--- m dump:\n%s\n\n", string(d))
-}
-```
-
-This example will generate the following output:
-
-```
---- t:
-{Easy! {2 [3 4]}}
-
---- t dump:
-a: Easy!
-b:
- c: 2
- d: [3, 4]
-
-
---- m:
-map[a:Easy! b:map[c:2 d:[3 4]]]
-
---- m dump:
-a: Easy!
-b:
- c: 2
- d:
- - 3
- - 4
-```
-
diff --git a/vendor/go.yaml.in/yaml/v2/apic.go b/vendor/go.yaml.in/yaml/v2/apic.go
deleted file mode 100644
index acf71402cf..0000000000
--- a/vendor/go.yaml.in/yaml/v2/apic.go
+++ /dev/null
@@ -1,744 +0,0 @@
-package yaml
-
-import (
- "io"
-)
-
-func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
- //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
-
- // Check if we can move the queue at the beginning of the buffer.
- if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
- if parser.tokens_head != len(parser.tokens) {
- copy(parser.tokens, parser.tokens[parser.tokens_head:])
- }
- parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
- parser.tokens_head = 0
- }
- parser.tokens = append(parser.tokens, *token)
- if pos < 0 {
- return
- }
- copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
- parser.tokens[parser.tokens_head+pos] = *token
-}
-
-// Create a new parser object.
-func yaml_parser_initialize(parser *yaml_parser_t) bool {
- *parser = yaml_parser_t{
- raw_buffer: make([]byte, 0, input_raw_buffer_size),
- buffer: make([]byte, 0, input_buffer_size),
- }
- return true
-}
-
-// Destroy a parser object.
-func yaml_parser_delete(parser *yaml_parser_t) {
- *parser = yaml_parser_t{}
-}
-
-// String read handler.
-func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
- if parser.input_pos == len(parser.input) {
- return 0, io.EOF
- }
- n = copy(buffer, parser.input[parser.input_pos:])
- parser.input_pos += n
- return n, nil
-}
-
-// Reader read handler.
-func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
- return parser.input_reader.Read(buffer)
-}
-
-// Set a string input.
-func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
- if parser.read_handler != nil {
- panic("must set the input source only once")
- }
- parser.read_handler = yaml_string_read_handler
- parser.input = input
- parser.input_pos = 0
-}
-
-// Set a file input.
-func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
- if parser.read_handler != nil {
- panic("must set the input source only once")
- }
- parser.read_handler = yaml_reader_read_handler
- parser.input_reader = r
-}
-
-// Set the source encoding.
-func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
- if parser.encoding != yaml_ANY_ENCODING {
- panic("must set the encoding only once")
- }
- parser.encoding = encoding
-}
-
-var disableLineWrapping = false
-
-// Create a new emitter object.
-func yaml_emitter_initialize(emitter *yaml_emitter_t) {
- *emitter = yaml_emitter_t{
- buffer: make([]byte, output_buffer_size),
- raw_buffer: make([]byte, 0, output_raw_buffer_size),
- states: make([]yaml_emitter_state_t, 0, initial_stack_size),
- events: make([]yaml_event_t, 0, initial_queue_size),
- }
- if disableLineWrapping {
- emitter.best_width = -1
- }
-}
-
-// Destroy an emitter object.
-func yaml_emitter_delete(emitter *yaml_emitter_t) {
- *emitter = yaml_emitter_t{}
-}
-
-// String write handler.
-func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
- *emitter.output_buffer = append(*emitter.output_buffer, buffer...)
- return nil
-}
-
-// yaml_writer_write_handler uses emitter.output_writer to write the
-// emitted text.
-func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
- _, err := emitter.output_writer.Write(buffer)
- return err
-}
-
-// Set a string output.
-func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
- if emitter.write_handler != nil {
- panic("must set the output target only once")
- }
- emitter.write_handler = yaml_string_write_handler
- emitter.output_buffer = output_buffer
-}
-
-// Set a file output.
-func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
- if emitter.write_handler != nil {
- panic("must set the output target only once")
- }
- emitter.write_handler = yaml_writer_write_handler
- emitter.output_writer = w
-}
-
-// Set the output encoding.
-func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
- if emitter.encoding != yaml_ANY_ENCODING {
- panic("must set the output encoding only once")
- }
- emitter.encoding = encoding
-}
-
-// Set the canonical output style.
-func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
- emitter.canonical = canonical
-}
-
-//// Set the indentation increment.
-func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
- if indent < 2 || indent > 9 {
- indent = 2
- }
- emitter.best_indent = indent
-}
-
-// Set the preferred line width.
-func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
- if width < 0 {
- width = -1
- }
- emitter.best_width = width
-}
-
-// Set if unescaped non-ASCII characters are allowed.
-func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
- emitter.unicode = unicode
-}
-
-// Set the preferred line break character.
-func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
- emitter.line_break = line_break
-}
-
-///*
-// * Destroy a token object.
-// */
-//
-//YAML_DECLARE(void)
-//yaml_token_delete(yaml_token_t *token)
-//{
-// assert(token); // Non-NULL token object expected.
-//
-// switch (token.type)
-// {
-// case YAML_TAG_DIRECTIVE_TOKEN:
-// yaml_free(token.data.tag_directive.handle);
-// yaml_free(token.data.tag_directive.prefix);
-// break;
-//
-// case YAML_ALIAS_TOKEN:
-// yaml_free(token.data.alias.value);
-// break;
-//
-// case YAML_ANCHOR_TOKEN:
-// yaml_free(token.data.anchor.value);
-// break;
-//
-// case YAML_TAG_TOKEN:
-// yaml_free(token.data.tag.handle);
-// yaml_free(token.data.tag.suffix);
-// break;
-//
-// case YAML_SCALAR_TOKEN:
-// yaml_free(token.data.scalar.value);
-// break;
-//
-// default:
-// break;
-// }
-//
-// memset(token, 0, sizeof(yaml_token_t));
-//}
-//
-///*
-// * Check if a string is a valid UTF-8 sequence.
-// *
-// * Check 'reader.c' for more details on UTF-8 encoding.
-// */
-//
-//static int
-//yaml_check_utf8(yaml_char_t *start, size_t length)
-//{
-// yaml_char_t *end = start+length;
-// yaml_char_t *pointer = start;
-//
-// while (pointer < end) {
-// unsigned char octet;
-// unsigned int width;
-// unsigned int value;
-// size_t k;
-//
-// octet = pointer[0];
-// width = (octet & 0x80) == 0x00 ? 1 :
-// (octet & 0xE0) == 0xC0 ? 2 :
-// (octet & 0xF0) == 0xE0 ? 3 :
-// (octet & 0xF8) == 0xF0 ? 4 : 0;
-// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
-// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
-// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
-// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
-// if (!width) return 0;
-// if (pointer+width > end) return 0;
-// for (k = 1; k < width; k ++) {
-// octet = pointer[k];
-// if ((octet & 0xC0) != 0x80) return 0;
-// value = (value << 6) + (octet & 0x3F);
-// }
-// if (!((width == 1) ||
-// (width == 2 && value >= 0x80) ||
-// (width == 3 && value >= 0x800) ||
-// (width == 4 && value >= 0x10000))) return 0;
-//
-// pointer += width;
-// }
-//
-// return 1;
-//}
-//
-
-// Create STREAM-START.
-func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
- *event = yaml_event_t{
- typ: yaml_STREAM_START_EVENT,
- encoding: encoding,
- }
-}
-
-// Create STREAM-END.
-func yaml_stream_end_event_initialize(event *yaml_event_t) {
- *event = yaml_event_t{
- typ: yaml_STREAM_END_EVENT,
- }
-}
-
-// Create DOCUMENT-START.
-func yaml_document_start_event_initialize(
- event *yaml_event_t,
- version_directive *yaml_version_directive_t,
- tag_directives []yaml_tag_directive_t,
- implicit bool,
-) {
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_START_EVENT,
- version_directive: version_directive,
- tag_directives: tag_directives,
- implicit: implicit,
- }
-}
-
-// Create DOCUMENT-END.
-func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_END_EVENT,
- implicit: implicit,
- }
-}
-
-///*
-// * Create ALIAS.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t)
-//{
-// mark yaml_mark_t = { 0, 0, 0 }
-// anchor_copy *yaml_char_t = NULL
-//
-// assert(event) // Non-NULL event object is expected.
-// assert(anchor) // Non-NULL anchor is expected.
-//
-// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0
-//
-// anchor_copy = yaml_strdup(anchor)
-// if (!anchor_copy)
-// return 0
-//
-// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark)
-//
-// return 1
-//}
-
-// Create SCALAR.
-func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- anchor: anchor,
- tag: tag,
- value: value,
- implicit: plain_implicit,
- quoted_implicit: quoted_implicit,
- style: yaml_style_t(style),
- }
- return true
-}
-
-// Create SEQUENCE-START.
-func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(style),
- }
- return true
-}
-
-// Create SEQUENCE-END.
-func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- }
- return true
-}
-
-// Create MAPPING-START.
-func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(style),
- }
-}
-
-// Create MAPPING-END.
-func yaml_mapping_end_event_initialize(event *yaml_event_t) {
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- }
-}
-
-// Destroy an event object.
-func yaml_event_delete(event *yaml_event_t) {
- *event = yaml_event_t{}
-}
-
-///*
-// * Create a document object.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_initialize(document *yaml_document_t,
-// version_directive *yaml_version_directive_t,
-// tag_directives_start *yaml_tag_directive_t,
-// tag_directives_end *yaml_tag_directive_t,
-// start_implicit int, end_implicit int)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// struct {
-// start *yaml_node_t
-// end *yaml_node_t
-// top *yaml_node_t
-// } nodes = { NULL, NULL, NULL }
-// version_directive_copy *yaml_version_directive_t = NULL
-// struct {
-// start *yaml_tag_directive_t
-// end *yaml_tag_directive_t
-// top *yaml_tag_directive_t
-// } tag_directives_copy = { NULL, NULL, NULL }
-// value yaml_tag_directive_t = { NULL, NULL }
-// mark yaml_mark_t = { 0, 0, 0 }
-//
-// assert(document) // Non-NULL document object is expected.
-// assert((tag_directives_start && tag_directives_end) ||
-// (tag_directives_start == tag_directives_end))
-// // Valid tag directives are expected.
-//
-// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
-//
-// if (version_directive) {
-// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
-// if (!version_directive_copy) goto error
-// version_directive_copy.major = version_directive.major
-// version_directive_copy.minor = version_directive.minor
-// }
-//
-// if (tag_directives_start != tag_directives_end) {
-// tag_directive *yaml_tag_directive_t
-// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
-// goto error
-// for (tag_directive = tag_directives_start
-// tag_directive != tag_directives_end; tag_directive ++) {
-// assert(tag_directive.handle)
-// assert(tag_directive.prefix)
-// if (!yaml_check_utf8(tag_directive.handle,
-// strlen((char *)tag_directive.handle)))
-// goto error
-// if (!yaml_check_utf8(tag_directive.prefix,
-// strlen((char *)tag_directive.prefix)))
-// goto error
-// value.handle = yaml_strdup(tag_directive.handle)
-// value.prefix = yaml_strdup(tag_directive.prefix)
-// if (!value.handle || !value.prefix) goto error
-// if (!PUSH(&context, tag_directives_copy, value))
-// goto error
-// value.handle = NULL
-// value.prefix = NULL
-// }
-// }
-//
-// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
-// tag_directives_copy.start, tag_directives_copy.top,
-// start_implicit, end_implicit, mark, mark)
-//
-// return 1
-//
-//error:
-// STACK_DEL(&context, nodes)
-// yaml_free(version_directive_copy)
-// while (!STACK_EMPTY(&context, tag_directives_copy)) {
-// value yaml_tag_directive_t = POP(&context, tag_directives_copy)
-// yaml_free(value.handle)
-// yaml_free(value.prefix)
-// }
-// STACK_DEL(&context, tag_directives_copy)
-// yaml_free(value.handle)
-// yaml_free(value.prefix)
-//
-// return 0
-//}
-//
-///*
-// * Destroy a document object.
-// */
-//
-//YAML_DECLARE(void)
-//yaml_document_delete(document *yaml_document_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// tag_directive *yaml_tag_directive_t
-//
-// context.error = YAML_NO_ERROR // Eliminate a compiler warning.
-//
-// assert(document) // Non-NULL document object is expected.
-//
-// while (!STACK_EMPTY(&context, document.nodes)) {
-// node yaml_node_t = POP(&context, document.nodes)
-// yaml_free(node.tag)
-// switch (node.type) {
-// case YAML_SCALAR_NODE:
-// yaml_free(node.data.scalar.value)
-// break
-// case YAML_SEQUENCE_NODE:
-// STACK_DEL(&context, node.data.sequence.items)
-// break
-// case YAML_MAPPING_NODE:
-// STACK_DEL(&context, node.data.mapping.pairs)
-// break
-// default:
-// assert(0) // Should not happen.
-// }
-// }
-// STACK_DEL(&context, document.nodes)
-//
-// yaml_free(document.version_directive)
-// for (tag_directive = document.tag_directives.start
-// tag_directive != document.tag_directives.end
-// tag_directive++) {
-// yaml_free(tag_directive.handle)
-// yaml_free(tag_directive.prefix)
-// }
-// yaml_free(document.tag_directives.start)
-//
-// memset(document, 0, sizeof(yaml_document_t))
-//}
-//
-///**
-// * Get a document node.
-// */
-//
-//YAML_DECLARE(yaml_node_t *)
-//yaml_document_get_node(document *yaml_document_t, index int)
-//{
-// assert(document) // Non-NULL document object is expected.
-//
-// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
-// return document.nodes.start + index - 1
-// }
-// return NULL
-//}
-//
-///**
-// * Get the root object.
-// */
-//
-//YAML_DECLARE(yaml_node_t *)
-//yaml_document_get_root_node(document *yaml_document_t)
-//{
-// assert(document) // Non-NULL document object is expected.
-//
-// if (document.nodes.top != document.nodes.start) {
-// return document.nodes.start
-// }
-// return NULL
-//}
-//
-///*
-// * Add a scalar node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_scalar(document *yaml_document_t,
-// tag *yaml_char_t, value *yaml_char_t, length int,
-// style yaml_scalar_style_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// mark yaml_mark_t = { 0, 0, 0 }
-// tag_copy *yaml_char_t = NULL
-// value_copy *yaml_char_t = NULL
-// node yaml_node_t
-//
-// assert(document) // Non-NULL document object is expected.
-// assert(value) // Non-NULL value is expected.
-//
-// if (!tag) {
-// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
-// }
-//
-// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-// tag_copy = yaml_strdup(tag)
-// if (!tag_copy) goto error
-//
-// if (length < 0) {
-// length = strlen((char *)value)
-// }
-//
-// if (!yaml_check_utf8(value, length)) goto error
-// value_copy = yaml_malloc(length+1)
-// if (!value_copy) goto error
-// memcpy(value_copy, value, length)
-// value_copy[length] = '\0'
-//
-// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
-// if (!PUSH(&context, document.nodes, node)) goto error
-//
-// return document.nodes.top - document.nodes.start
-//
-//error:
-// yaml_free(tag_copy)
-// yaml_free(value_copy)
-//
-// return 0
-//}
-//
-///*
-// * Add a sequence node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_sequence(document *yaml_document_t,
-// tag *yaml_char_t, style yaml_sequence_style_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// mark yaml_mark_t = { 0, 0, 0 }
-// tag_copy *yaml_char_t = NULL
-// struct {
-// start *yaml_node_item_t
-// end *yaml_node_item_t
-// top *yaml_node_item_t
-// } items = { NULL, NULL, NULL }
-// node yaml_node_t
-//
-// assert(document) // Non-NULL document object is expected.
-//
-// if (!tag) {
-// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
-// }
-//
-// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-// tag_copy = yaml_strdup(tag)
-// if (!tag_copy) goto error
-//
-// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
-//
-// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
-// style, mark, mark)
-// if (!PUSH(&context, document.nodes, node)) goto error
-//
-// return document.nodes.top - document.nodes.start
-//
-//error:
-// STACK_DEL(&context, items)
-// yaml_free(tag_copy)
-//
-// return 0
-//}
-//
-///*
-// * Add a mapping node to a document.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_add_mapping(document *yaml_document_t,
-// tag *yaml_char_t, style yaml_mapping_style_t)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-// mark yaml_mark_t = { 0, 0, 0 }
-// tag_copy *yaml_char_t = NULL
-// struct {
-// start *yaml_node_pair_t
-// end *yaml_node_pair_t
-// top *yaml_node_pair_t
-// } pairs = { NULL, NULL, NULL }
-// node yaml_node_t
-//
-// assert(document) // Non-NULL document object is expected.
-//
-// if (!tag) {
-// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
-// }
-//
-// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
-// tag_copy = yaml_strdup(tag)
-// if (!tag_copy) goto error
-//
-// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
-//
-// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
-// style, mark, mark)
-// if (!PUSH(&context, document.nodes, node)) goto error
-//
-// return document.nodes.top - document.nodes.start
-//
-//error:
-// STACK_DEL(&context, pairs)
-// yaml_free(tag_copy)
-//
-// return 0
-//}
-//
-///*
-// * Append an item to a sequence node.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_append_sequence_item(document *yaml_document_t,
-// sequence int, item int)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-//
-// assert(document) // Non-NULL document is required.
-// assert(sequence > 0
-// && document.nodes.start + sequence <= document.nodes.top)
-// // Valid sequence id is required.
-// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
-// // A sequence node is required.
-// assert(item > 0 && document.nodes.start + item <= document.nodes.top)
-// // Valid item id is required.
-//
-// if (!PUSH(&context,
-// document.nodes.start[sequence-1].data.sequence.items, item))
-// return 0
-//
-// return 1
-//}
-//
-///*
-// * Append a pair of a key and a value to a mapping node.
-// */
-//
-//YAML_DECLARE(int)
-//yaml_document_append_mapping_pair(document *yaml_document_t,
-// mapping int, key int, value int)
-//{
-// struct {
-// error yaml_error_type_t
-// } context
-//
-// pair yaml_node_pair_t
-//
-// assert(document) // Non-NULL document is required.
-// assert(mapping > 0
-// && document.nodes.start + mapping <= document.nodes.top)
-// // Valid mapping id is required.
-// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
-// // A mapping node is required.
-// assert(key > 0 && document.nodes.start + key <= document.nodes.top)
-// // Valid key id is required.
-// assert(value > 0 && document.nodes.start + value <= document.nodes.top)
-// // Valid value id is required.
-//
-// pair.key = key
-// pair.value = value
-//
-// if (!PUSH(&context,
-// document.nodes.start[mapping-1].data.mapping.pairs, pair))
-// return 0
-//
-// return 1
-//}
-//
-//
diff --git a/vendor/go.yaml.in/yaml/v2/decode.go b/vendor/go.yaml.in/yaml/v2/decode.go
deleted file mode 100644
index 129bc2a97d..0000000000
--- a/vendor/go.yaml.in/yaml/v2/decode.go
+++ /dev/null
@@ -1,815 +0,0 @@
-package yaml
-
-import (
- "encoding"
- "encoding/base64"
- "fmt"
- "io"
- "math"
- "reflect"
- "strconv"
- "time"
-)
-
-const (
- documentNode = 1 << iota
- mappingNode
- sequenceNode
- scalarNode
- aliasNode
-)
-
-type node struct {
- kind int
- line, column int
- tag string
- // For an alias node, alias holds the resolved alias.
- alias *node
- value string
- implicit bool
- children []*node
- anchors map[string]*node
-}
-
-// ----------------------------------------------------------------------------
-// Parser, produces a node tree out of a libyaml event stream.
-
-type parser struct {
- parser yaml_parser_t
- event yaml_event_t
- doc *node
- doneInit bool
-}
-
-func newParser(b []byte) *parser {
- p := parser{}
- if !yaml_parser_initialize(&p.parser) {
- panic("failed to initialize YAML emitter")
- }
- if len(b) == 0 {
- b = []byte{'\n'}
- }
- yaml_parser_set_input_string(&p.parser, b)
- return &p
-}
-
-func newParserFromReader(r io.Reader) *parser {
- p := parser{}
- if !yaml_parser_initialize(&p.parser) {
- panic("failed to initialize YAML emitter")
- }
- yaml_parser_set_input_reader(&p.parser, r)
- return &p
-}
-
-func (p *parser) init() {
- if p.doneInit {
- return
- }
- p.expect(yaml_STREAM_START_EVENT)
- p.doneInit = true
-}
-
-func (p *parser) destroy() {
- if p.event.typ != yaml_NO_EVENT {
- yaml_event_delete(&p.event)
- }
- yaml_parser_delete(&p.parser)
-}
-
-// expect consumes an event from the event stream and
-// checks that it's of the expected type.
-func (p *parser) expect(e yaml_event_type_t) {
- if p.event.typ == yaml_NO_EVENT {
- if !yaml_parser_parse(&p.parser, &p.event) {
- p.fail()
- }
- }
- if p.event.typ == yaml_STREAM_END_EVENT {
- failf("attempted to go past the end of stream; corrupted value?")
- }
- if p.event.typ != e {
- p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
- p.fail()
- }
- yaml_event_delete(&p.event)
- p.event.typ = yaml_NO_EVENT
-}
-
-// peek peeks at the next event in the event stream,
-// puts the results into p.event and returns the event type.
-func (p *parser) peek() yaml_event_type_t {
- if p.event.typ != yaml_NO_EVENT {
- return p.event.typ
- }
- if !yaml_parser_parse(&p.parser, &p.event) {
- p.fail()
- }
- return p.event.typ
-}
-
-func (p *parser) fail() {
- var where string
- var line int
- if p.parser.problem_mark.line != 0 {
- line = p.parser.problem_mark.line
- // Scanner errors don't iterate line before returning error
- if p.parser.error == yaml_SCANNER_ERROR {
- line++
- }
- } else if p.parser.context_mark.line != 0 {
- line = p.parser.context_mark.line
- }
- if line != 0 {
- where = "line " + strconv.Itoa(line) + ": "
- }
- var msg string
- if len(p.parser.problem) > 0 {
- msg = p.parser.problem
- } else {
- msg = "unknown problem parsing YAML content"
- }
- failf("%s%s", where, msg)
-}
-
-func (p *parser) anchor(n *node, anchor []byte) {
- if anchor != nil {
- p.doc.anchors[string(anchor)] = n
- }
-}
-
-func (p *parser) parse() *node {
- p.init()
- switch p.peek() {
- case yaml_SCALAR_EVENT:
- return p.scalar()
- case yaml_ALIAS_EVENT:
- return p.alias()
- case yaml_MAPPING_START_EVENT:
- return p.mapping()
- case yaml_SEQUENCE_START_EVENT:
- return p.sequence()
- case yaml_DOCUMENT_START_EVENT:
- return p.document()
- case yaml_STREAM_END_EVENT:
- // Happens when attempting to decode an empty buffer.
- return nil
- default:
- panic("attempted to parse unknown event: " + p.event.typ.String())
- }
-}
-
-func (p *parser) node(kind int) *node {
- return &node{
- kind: kind,
- line: p.event.start_mark.line,
- column: p.event.start_mark.column,
- }
-}
-
-func (p *parser) document() *node {
- n := p.node(documentNode)
- n.anchors = make(map[string]*node)
- p.doc = n
- p.expect(yaml_DOCUMENT_START_EVENT)
- n.children = append(n.children, p.parse())
- p.expect(yaml_DOCUMENT_END_EVENT)
- return n
-}
-
-func (p *parser) alias() *node {
- n := p.node(aliasNode)
- n.value = string(p.event.anchor)
- n.alias = p.doc.anchors[n.value]
- if n.alias == nil {
- failf("unknown anchor '%s' referenced", n.value)
- }
- p.expect(yaml_ALIAS_EVENT)
- return n
-}
-
-func (p *parser) scalar() *node {
- n := p.node(scalarNode)
- n.value = string(p.event.value)
- n.tag = string(p.event.tag)
- n.implicit = p.event.implicit
- p.anchor(n, p.event.anchor)
- p.expect(yaml_SCALAR_EVENT)
- return n
-}
-
-func (p *parser) sequence() *node {
- n := p.node(sequenceNode)
- p.anchor(n, p.event.anchor)
- p.expect(yaml_SEQUENCE_START_EVENT)
- for p.peek() != yaml_SEQUENCE_END_EVENT {
- n.children = append(n.children, p.parse())
- }
- p.expect(yaml_SEQUENCE_END_EVENT)
- return n
-}
-
-func (p *parser) mapping() *node {
- n := p.node(mappingNode)
- p.anchor(n, p.event.anchor)
- p.expect(yaml_MAPPING_START_EVENT)
- for p.peek() != yaml_MAPPING_END_EVENT {
- n.children = append(n.children, p.parse(), p.parse())
- }
- p.expect(yaml_MAPPING_END_EVENT)
- return n
-}
-
-// ----------------------------------------------------------------------------
-// Decoder, unmarshals a node into a provided value.
-
-type decoder struct {
- doc *node
- aliases map[*node]bool
- mapType reflect.Type
- terrors []string
- strict bool
-
- decodeCount int
- aliasCount int
- aliasDepth int
-}
-
-var (
- mapItemType = reflect.TypeOf(MapItem{})
- durationType = reflect.TypeOf(time.Duration(0))
- defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
- ifaceType = defaultMapType.Elem()
- timeType = reflect.TypeOf(time.Time{})
- ptrTimeType = reflect.TypeOf(&time.Time{})
-)
-
-func newDecoder(strict bool) *decoder {
- d := &decoder{mapType: defaultMapType, strict: strict}
- d.aliases = make(map[*node]bool)
- return d
-}
-
-func (d *decoder) terror(n *node, tag string, out reflect.Value) {
- if n.tag != "" {
- tag = n.tag
- }
- value := n.value
- if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
- if len(value) > 10 {
- value = " `" + value[:7] + "...`"
- } else {
- value = " `" + value + "`"
- }
- }
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
-}
-
-func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
- terrlen := len(d.terrors)
- err := u.UnmarshalYAML(func(v interface{}) (err error) {
- defer handleErr(&err)
- d.unmarshal(n, reflect.ValueOf(v))
- if len(d.terrors) > terrlen {
- issues := d.terrors[terrlen:]
- d.terrors = d.terrors[:terrlen]
- return &TypeError{issues}
- }
- return nil
- })
- if e, ok := err.(*TypeError); ok {
- d.terrors = append(d.terrors, e.Errors...)
- return false
- }
- if err != nil {
- fail(err)
- }
- return true
-}
-
-// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
-// if a value is found to implement it.
-// It returns the initialized and dereferenced out value, whether
-// unmarshalling was already done by UnmarshalYAML, and if so whether
-// its types unmarshalled appropriately.
-//
-// If n holds a null value, prepare returns before doing anything.
-func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
- if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
- return out, false, false
- }
- again := true
- for again {
- again = false
- if out.Kind() == reflect.Ptr {
- if out.IsNil() {
- out.Set(reflect.New(out.Type().Elem()))
- }
- out = out.Elem()
- again = true
- }
- if out.CanAddr() {
- if u, ok := out.Addr().Interface().(Unmarshaler); ok {
- good = d.callUnmarshaler(n, u)
- return out, true, good
- }
- }
- }
- return out, false, false
-}
-
-const (
- // 400,000 decode operations is ~500kb of dense object declarations, or
- // ~5kb of dense object declarations with 10000% alias expansion
- alias_ratio_range_low = 400000
-
- // 4,000,000 decode operations is ~5MB of dense object declarations, or
- // ~4.5MB of dense object declarations with 10% alias expansion
- alias_ratio_range_high = 4000000
-
- // alias_ratio_range is the range over which we scale allowed alias ratios
- alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
-)
-
-func allowedAliasRatio(decodeCount int) float64 {
- switch {
- case decodeCount <= alias_ratio_range_low:
- // allow 99% to come from alias expansion for small-to-medium documents
- return 0.99
- case decodeCount >= alias_ratio_range_high:
- // allow 10% to come from alias expansion for very large documents
- return 0.10
- default:
- // scale smoothly from 99% down to 10% over the range.
- // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
- // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
- return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
- }
-}
-
-func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
- d.decodeCount++
- if d.aliasDepth > 0 {
- d.aliasCount++
- }
- if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
- failf("document contains excessive aliasing")
- }
- switch n.kind {
- case documentNode:
- return d.document(n, out)
- case aliasNode:
- return d.alias(n, out)
- }
- out, unmarshaled, good := d.prepare(n, out)
- if unmarshaled {
- return good
- }
- switch n.kind {
- case scalarNode:
- good = d.scalar(n, out)
- case mappingNode:
- good = d.mapping(n, out)
- case sequenceNode:
- good = d.sequence(n, out)
- default:
- panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
- }
- return good
-}
-
-func (d *decoder) document(n *node, out reflect.Value) (good bool) {
- if len(n.children) == 1 {
- d.doc = n
- d.unmarshal(n.children[0], out)
- return true
- }
- return false
-}
-
-func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
- if d.aliases[n] {
- // TODO this could actually be allowed in some circumstances.
- failf("anchor '%s' value contains itself", n.value)
- }
- d.aliases[n] = true
- d.aliasDepth++
- good = d.unmarshal(n.alias, out)
- d.aliasDepth--
- delete(d.aliases, n)
- return good
-}
-
-var zeroValue reflect.Value
-
-func resetMap(out reflect.Value) {
- for _, k := range out.MapKeys() {
- out.SetMapIndex(k, zeroValue)
- }
-}
-
-func (d *decoder) scalar(n *node, out reflect.Value) bool {
- var tag string
- var resolved interface{}
- if n.tag == "" && !n.implicit {
- tag = yaml_STR_TAG
- resolved = n.value
- } else {
- tag, resolved = resolve(n.tag, n.value)
- if tag == yaml_BINARY_TAG {
- data, err := base64.StdEncoding.DecodeString(resolved.(string))
- if err != nil {
- failf("!!binary value contains invalid base64 data")
- }
- resolved = string(data)
- }
- }
- if resolved == nil {
- if out.Kind() == reflect.Map && !out.CanAddr() {
- resetMap(out)
- } else {
- out.Set(reflect.Zero(out.Type()))
- }
- return true
- }
- if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
- // We've resolved to exactly the type we want, so use that.
- out.Set(resolvedv)
- return true
- }
- // Perhaps we can use the value as a TextUnmarshaler to
- // set its value.
- if out.CanAddr() {
- u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
- if ok {
- var text []byte
- if tag == yaml_BINARY_TAG {
- text = []byte(resolved.(string))
- } else {
- // We let any value be unmarshaled into TextUnmarshaler.
- // That might be more lax than we'd like, but the
- // TextUnmarshaler itself should bowl out any dubious values.
- text = []byte(n.value)
- }
- err := u.UnmarshalText(text)
- if err != nil {
- fail(err)
- }
- return true
- }
- }
- switch out.Kind() {
- case reflect.String:
- if tag == yaml_BINARY_TAG {
- out.SetString(resolved.(string))
- return true
- }
- if resolved != nil {
- out.SetString(n.value)
- return true
- }
- case reflect.Interface:
- if resolved == nil {
- out.Set(reflect.Zero(out.Type()))
- } else if tag == yaml_TIMESTAMP_TAG {
- // It looks like a timestamp but for backward compatibility
- // reasons we set it as a string, so that code that unmarshals
- // timestamp-like values into interface{} will continue to
- // see a string and not a time.Time.
- // TODO(v3) Drop this.
- out.Set(reflect.ValueOf(n.value))
- } else {
- out.Set(reflect.ValueOf(resolved))
- }
- return true
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- switch resolved := resolved.(type) {
- case int:
- if !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- return true
- }
- case int64:
- if !out.OverflowInt(resolved) {
- out.SetInt(resolved)
- return true
- }
- case uint64:
- if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- return true
- }
- case float64:
- if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- return true
- }
- case string:
- if out.Type() == durationType {
- d, err := time.ParseDuration(resolved)
- if err == nil {
- out.SetInt(int64(d))
- return true
- }
- }
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- switch resolved := resolved.(type) {
- case int:
- if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- case int64:
- if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- case uint64:
- if !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- case float64:
- if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- return true
- }
- }
- case reflect.Bool:
- switch resolved := resolved.(type) {
- case bool:
- out.SetBool(resolved)
- return true
- }
- case reflect.Float32, reflect.Float64:
- switch resolved := resolved.(type) {
- case int:
- out.SetFloat(float64(resolved))
- return true
- case int64:
- out.SetFloat(float64(resolved))
- return true
- case uint64:
- out.SetFloat(float64(resolved))
- return true
- case float64:
- out.SetFloat(resolved)
- return true
- }
- case reflect.Struct:
- if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
- out.Set(resolvedv)
- return true
- }
- case reflect.Ptr:
- if out.Type().Elem() == reflect.TypeOf(resolved) {
- // TODO DOes this make sense? When is out a Ptr except when decoding a nil value?
- elem := reflect.New(out.Type().Elem())
- elem.Elem().Set(reflect.ValueOf(resolved))
- out.Set(elem)
- return true
- }
- }
- d.terror(n, tag, out)
- return false
-}
-
-func settableValueOf(i interface{}) reflect.Value {
- v := reflect.ValueOf(i)
- sv := reflect.New(v.Type()).Elem()
- sv.Set(v)
- return sv
-}
-
-func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
- l := len(n.children)
-
- var iface reflect.Value
- switch out.Kind() {
- case reflect.Slice:
- out.Set(reflect.MakeSlice(out.Type(), l, l))
- case reflect.Array:
- if l != out.Len() {
- failf("invalid array: want %d elements but got %d", out.Len(), l)
- }
- case reflect.Interface:
- // No type hints. Will have to use a generic sequence.
- iface = out
- out = settableValueOf(make([]interface{}, l))
- default:
- d.terror(n, yaml_SEQ_TAG, out)
- return false
- }
- et := out.Type().Elem()
-
- j := 0
- for i := 0; i < l; i++ {
- e := reflect.New(et).Elem()
- if ok := d.unmarshal(n.children[i], e); ok {
- out.Index(j).Set(e)
- j++
- }
- }
- if out.Kind() != reflect.Array {
- out.Set(out.Slice(0, j))
- }
- if iface.IsValid() {
- iface.Set(out)
- }
- return true
-}
-
-func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
- switch out.Kind() {
- case reflect.Struct:
- return d.mappingStruct(n, out)
- case reflect.Slice:
- return d.mappingSlice(n, out)
- case reflect.Map:
- // okay
- case reflect.Interface:
- if d.mapType.Kind() == reflect.Map {
- iface := out
- out = reflect.MakeMap(d.mapType)
- iface.Set(out)
- } else {
- slicev := reflect.New(d.mapType).Elem()
- if !d.mappingSlice(n, slicev) {
- return false
- }
- out.Set(slicev)
- return true
- }
- default:
- d.terror(n, yaml_MAP_TAG, out)
- return false
- }
- outt := out.Type()
- kt := outt.Key()
- et := outt.Elem()
-
- mapType := d.mapType
- if outt.Key() == ifaceType && outt.Elem() == ifaceType {
- d.mapType = outt
- }
-
- if out.IsNil() {
- out.Set(reflect.MakeMap(outt))
- }
- l := len(n.children)
- for i := 0; i < l; i += 2 {
- if isMerge(n.children[i]) {
- d.merge(n.children[i+1], out)
- continue
- }
- k := reflect.New(kt).Elem()
- if d.unmarshal(n.children[i], k) {
- kkind := k.Kind()
- if kkind == reflect.Interface {
- kkind = k.Elem().Kind()
- }
- if kkind == reflect.Map || kkind == reflect.Slice {
- failf("invalid map key: %#v", k.Interface())
- }
- e := reflect.New(et).Elem()
- if d.unmarshal(n.children[i+1], e) {
- d.setMapIndex(n.children[i+1], out, k, e)
- }
- }
- }
- d.mapType = mapType
- return true
-}
-
-func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) {
- if d.strict && out.MapIndex(k) != zeroValue {
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface()))
- return
- }
- out.SetMapIndex(k, v)
-}
-
-func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
- outt := out.Type()
- if outt.Elem() != mapItemType {
- d.terror(n, yaml_MAP_TAG, out)
- return false
- }
-
- mapType := d.mapType
- d.mapType = outt
-
- var slice []MapItem
- var l = len(n.children)
- for i := 0; i < l; i += 2 {
- if isMerge(n.children[i]) {
- d.merge(n.children[i+1], out)
- continue
- }
- item := MapItem{}
- k := reflect.ValueOf(&item.Key).Elem()
- if d.unmarshal(n.children[i], k) {
- v := reflect.ValueOf(&item.Value).Elem()
- if d.unmarshal(n.children[i+1], v) {
- slice = append(slice, item)
- }
- }
- }
- out.Set(reflect.ValueOf(slice))
- d.mapType = mapType
- return true
-}
-
-func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
- sinfo, err := getStructInfo(out.Type())
- if err != nil {
- panic(err)
- }
- name := settableValueOf("")
- l := len(n.children)
-
- var inlineMap reflect.Value
- var elemType reflect.Type
- if sinfo.InlineMap != -1 {
- inlineMap = out.Field(sinfo.InlineMap)
- inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
- elemType = inlineMap.Type().Elem()
- }
-
- var doneFields []bool
- if d.strict {
- doneFields = make([]bool, len(sinfo.FieldsList))
- }
- for i := 0; i < l; i += 2 {
- ni := n.children[i]
- if isMerge(ni) {
- d.merge(n.children[i+1], out)
- continue
- }
- if !d.unmarshal(ni, name) {
- continue
- }
- if info, ok := sinfo.FieldsMap[name.String()]; ok {
- if d.strict {
- if doneFields[info.Id] {
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type()))
- continue
- }
- doneFields[info.Id] = true
- }
- var field reflect.Value
- if info.Inline == nil {
- field = out.Field(info.Num)
- } else {
- field = out.FieldByIndex(info.Inline)
- }
- d.unmarshal(n.children[i+1], field)
- } else if sinfo.InlineMap != -1 {
- if inlineMap.IsNil() {
- inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
- }
- value := reflect.New(elemType).Elem()
- d.unmarshal(n.children[i+1], value)
- d.setMapIndex(n.children[i+1], inlineMap, name, value)
- } else if d.strict {
- d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type()))
- }
- }
- return true
-}
-
-func failWantMap() {
- failf("map merge requires map or sequence of maps as the value")
-}
-
-func (d *decoder) merge(n *node, out reflect.Value) {
- switch n.kind {
- case mappingNode:
- d.unmarshal(n, out)
- case aliasNode:
- if n.alias != nil && n.alias.kind != mappingNode {
- failWantMap()
- }
- d.unmarshal(n, out)
- case sequenceNode:
- // Step backwards as earlier nodes take precedence.
- for i := len(n.children) - 1; i >= 0; i-- {
- ni := n.children[i]
- if ni.kind == aliasNode {
- if ni.alias != nil && ni.alias.kind != mappingNode {
- failWantMap()
- }
- } else if ni.kind != mappingNode {
- failWantMap()
- }
- d.unmarshal(ni, out)
- }
- default:
- failWantMap()
- }
-}
-
-func isMerge(n *node) bool {
- return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
-}
diff --git a/vendor/go.yaml.in/yaml/v2/emitterc.go b/vendor/go.yaml.in/yaml/v2/emitterc.go
deleted file mode 100644
index a1c2cc5262..0000000000
--- a/vendor/go.yaml.in/yaml/v2/emitterc.go
+++ /dev/null
@@ -1,1685 +0,0 @@
-package yaml
-
-import (
- "bytes"
- "fmt"
-)
-
-// Flush the buffer if needed.
-func flush(emitter *yaml_emitter_t) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) {
- return yaml_emitter_flush(emitter)
- }
- return true
-}
-
-// Put a character to the output buffer.
-func put(emitter *yaml_emitter_t, value byte) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
- return false
- }
- emitter.buffer[emitter.buffer_pos] = value
- emitter.buffer_pos++
- emitter.column++
- return true
-}
-
-// Put a line break to the output buffer.
-func put_break(emitter *yaml_emitter_t) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
- return false
- }
- switch emitter.line_break {
- case yaml_CR_BREAK:
- emitter.buffer[emitter.buffer_pos] = '\r'
- emitter.buffer_pos += 1
- case yaml_LN_BREAK:
- emitter.buffer[emitter.buffer_pos] = '\n'
- emitter.buffer_pos += 1
- case yaml_CRLN_BREAK:
- emitter.buffer[emitter.buffer_pos+0] = '\r'
- emitter.buffer[emitter.buffer_pos+1] = '\n'
- emitter.buffer_pos += 2
- default:
- panic("unknown line break setting")
- }
- emitter.column = 0
- emitter.line++
- return true
-}
-
-// Copy a character from a string into buffer.
-func write(emitter *yaml_emitter_t, s []byte, i *int) bool {
- if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
- return false
- }
- p := emitter.buffer_pos
- w := width(s[*i])
- switch w {
- case 4:
- emitter.buffer[p+3] = s[*i+3]
- fallthrough
- case 3:
- emitter.buffer[p+2] = s[*i+2]
- fallthrough
- case 2:
- emitter.buffer[p+1] = s[*i+1]
- fallthrough
- case 1:
- emitter.buffer[p+0] = s[*i+0]
- default:
- panic("unknown character width")
- }
- emitter.column++
- emitter.buffer_pos += w
- *i += w
- return true
-}
-
-// Write a whole string into buffer.
-func write_all(emitter *yaml_emitter_t, s []byte) bool {
- for i := 0; i < len(s); {
- if !write(emitter, s, &i) {
- return false
- }
- }
- return true
-}
-
-// Copy a line break character from a string into buffer.
-func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool {
- if s[*i] == '\n' {
- if !put_break(emitter) {
- return false
- }
- *i++
- } else {
- if !write(emitter, s, i) {
- return false
- }
- emitter.column = 0
- emitter.line++
- }
- return true
-}
-
-// Set an emitter error and return false.
-func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
- emitter.error = yaml_EMITTER_ERROR
- emitter.problem = problem
- return false
-}
-
-// Emit an event.
-func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- emitter.events = append(emitter.events, *event)
- for !yaml_emitter_need_more_events(emitter) {
- event := &emitter.events[emitter.events_head]
- if !yaml_emitter_analyze_event(emitter, event) {
- return false
- }
- if !yaml_emitter_state_machine(emitter, event) {
- return false
- }
- yaml_event_delete(event)
- emitter.events_head++
- }
- return true
-}
-
-// Check if we need to accumulate more events before emitting.
-//
-// We accumulate extra
-// - 1 event for DOCUMENT-START
-// - 2 events for SEQUENCE-START
-// - 3 events for MAPPING-START
-//
-func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
- if emitter.events_head == len(emitter.events) {
- return true
- }
- var accumulate int
- switch emitter.events[emitter.events_head].typ {
- case yaml_DOCUMENT_START_EVENT:
- accumulate = 1
- break
- case yaml_SEQUENCE_START_EVENT:
- accumulate = 2
- break
- case yaml_MAPPING_START_EVENT:
- accumulate = 3
- break
- default:
- return false
- }
- if len(emitter.events)-emitter.events_head > accumulate {
- return false
- }
- var level int
- for i := emitter.events_head; i < len(emitter.events); i++ {
- switch emitter.events[i].typ {
- case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
- level++
- case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
- level--
- }
- if level == 0 {
- return false
- }
- }
- return true
-}
-
-// Append a directive to the directives stack.
-func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool {
- for i := 0; i < len(emitter.tag_directives); i++ {
- if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
- if allow_duplicates {
- return true
- }
- return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive")
- }
- }
-
- // [Go] Do we actually need to copy this given garbage collection
- // and the lack of deallocating destructors?
- tag_copy := yaml_tag_directive_t{
- handle: make([]byte, len(value.handle)),
- prefix: make([]byte, len(value.prefix)),
- }
- copy(tag_copy.handle, value.handle)
- copy(tag_copy.prefix, value.prefix)
- emitter.tag_directives = append(emitter.tag_directives, tag_copy)
- return true
-}
-
-// Increase the indentation level.
-func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool {
- emitter.indents = append(emitter.indents, emitter.indent)
- if emitter.indent < 0 {
- if flow {
- emitter.indent = emitter.best_indent
- } else {
- emitter.indent = 0
- }
- } else if !indentless {
- emitter.indent += emitter.best_indent
- }
- return true
-}
-
-// State dispatcher.
-func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- switch emitter.state {
- default:
- case yaml_EMIT_STREAM_START_STATE:
- return yaml_emitter_emit_stream_start(emitter, event)
-
- case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
- return yaml_emitter_emit_document_start(emitter, event, true)
-
- case yaml_EMIT_DOCUMENT_START_STATE:
- return yaml_emitter_emit_document_start(emitter, event, false)
-
- case yaml_EMIT_DOCUMENT_CONTENT_STATE:
- return yaml_emitter_emit_document_content(emitter, event)
-
- case yaml_EMIT_DOCUMENT_END_STATE:
- return yaml_emitter_emit_document_end(emitter, event)
-
- case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
- return yaml_emitter_emit_flow_sequence_item(emitter, event, true)
-
- case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
- return yaml_emitter_emit_flow_sequence_item(emitter, event, false)
-
- case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
- return yaml_emitter_emit_flow_mapping_key(emitter, event, true)
-
- case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
- return yaml_emitter_emit_flow_mapping_key(emitter, event, false)
-
- case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
- return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
-
- case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
- return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
-
- case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
- return yaml_emitter_emit_block_sequence_item(emitter, event, true)
-
- case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
- return yaml_emitter_emit_block_sequence_item(emitter, event, false)
-
- case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
- return yaml_emitter_emit_block_mapping_key(emitter, event, true)
-
- case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
- return yaml_emitter_emit_block_mapping_key(emitter, event, false)
-
- case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
- return yaml_emitter_emit_block_mapping_value(emitter, event, true)
-
- case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
- return yaml_emitter_emit_block_mapping_value(emitter, event, false)
-
- case yaml_EMIT_END_STATE:
- return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END")
- }
- panic("invalid emitter state")
-}
-
-// Expect STREAM-START.
-func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if event.typ != yaml_STREAM_START_EVENT {
- return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START")
- }
- if emitter.encoding == yaml_ANY_ENCODING {
- emitter.encoding = event.encoding
- if emitter.encoding == yaml_ANY_ENCODING {
- emitter.encoding = yaml_UTF8_ENCODING
- }
- }
- if emitter.best_indent < 2 || emitter.best_indent > 9 {
- emitter.best_indent = 2
- }
- if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
- emitter.best_width = 80
- }
- if emitter.best_width < 0 {
- emitter.best_width = 1<<31 - 1
- }
- if emitter.line_break == yaml_ANY_BREAK {
- emitter.line_break = yaml_LN_BREAK
- }
-
- emitter.indent = -1
- emitter.line = 0
- emitter.column = 0
- emitter.whitespace = true
- emitter.indention = true
-
- if emitter.encoding != yaml_UTF8_ENCODING {
- if !yaml_emitter_write_bom(emitter) {
- return false
- }
- }
- emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
- return true
-}
-
-// Expect DOCUMENT-START or STREAM-END.
-func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
-
- if event.typ == yaml_DOCUMENT_START_EVENT {
-
- if event.version_directive != nil {
- if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) {
- return false
- }
- }
-
- for i := 0; i < len(event.tag_directives); i++ {
- tag_directive := &event.tag_directives[i]
- if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
- return false
- }
- if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
- return false
- }
- }
-
- for i := 0; i < len(default_tag_directives); i++ {
- tag_directive := &default_tag_directives[i]
- if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) {
- return false
- }
- }
-
- implicit := event.implicit
- if !first || emitter.canonical {
- implicit = false
- }
-
- if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) {
- if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if event.version_directive != nil {
- implicit = false
- if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if len(event.tag_directives) > 0 {
- implicit = false
- for i := 0; i < len(event.tag_directives); i++ {
- tag_directive := &event.tag_directives[i]
- if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
- return false
- }
- if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- }
-
- if yaml_emitter_check_empty_document(emitter) {
- implicit = false
- }
- if !implicit {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
- return false
- }
- if emitter.canonical {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- }
-
- emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
- return true
- }
-
- if event.typ == yaml_STREAM_END_EVENT {
- if emitter.open_ended {
- if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_flush(emitter) {
- return false
- }
- emitter.state = yaml_EMIT_END_STATE
- return true
- }
-
- return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END")
-}
-
-// Expect the root node.
-func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
- return yaml_emitter_emit_node(emitter, event, true, false, false, false)
-}
-
-// Expect DOCUMENT-END.
-func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if event.typ != yaml_DOCUMENT_END_EVENT {
- return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END")
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !event.implicit {
- // [Go] Allocate the slice elsewhere.
- if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_flush(emitter) {
- return false
- }
- emitter.state = yaml_EMIT_DOCUMENT_START_STATE
- emitter.tag_directives = emitter.tag_directives[:0]
- return true
-}
-
-// Expect a flow item node.
-func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
- if first {
- if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) {
- return false
- }
- if !yaml_emitter_increase_indent(emitter, true, false) {
- return false
- }
- emitter.flow_level++
- }
-
- if event.typ == yaml_SEQUENCE_END_EVENT {
- emitter.flow_level--
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- if emitter.canonical && !first {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) {
- return false
- }
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
-
- return true
- }
-
- if !first {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
-
- if emitter.canonical || emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
- return yaml_emitter_emit_node(emitter, event, false, true, false, false)
-}
-
-// Expect a flow key node.
-func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
- if first {
- if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) {
- return false
- }
- if !yaml_emitter_increase_indent(emitter, true, false) {
- return false
- }
- emitter.flow_level++
- }
-
- if event.typ == yaml_MAPPING_END_EVENT {
- emitter.flow_level--
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- if emitter.canonical && !first {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) {
- return false
- }
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
- }
-
- if !first {
- if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
- return false
- }
- }
- if emitter.canonical || emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
-
- if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, true)
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) {
- return false
- }
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a flow value node.
-func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
- if simple {
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
- return false
- }
- } else {
- if emitter.canonical || emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) {
- return false
- }
- }
- emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a block item node.
-func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
- if first {
- if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) {
- return false
- }
- }
- if event.typ == yaml_SEQUENCE_END_EVENT {
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) {
- return false
- }
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
- return yaml_emitter_emit_node(emitter, event, false, true, false, false)
-}
-
-// Expect a block key node.
-func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
- if first {
- if !yaml_emitter_increase_indent(emitter, false, false) {
- return false
- }
- }
- if event.typ == yaml_MAPPING_END_EVENT {
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
- }
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if yaml_emitter_check_simple_key(emitter) {
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, true)
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) {
- return false
- }
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a block value node.
-func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
- if simple {
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
- return false
- }
- } else {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) {
- return false
- }
- }
- emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
- return yaml_emitter_emit_node(emitter, event, false, false, true, false)
-}
-
-// Expect a node.
-func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
- root bool, sequence bool, mapping bool, simple_key bool) bool {
-
- emitter.root_context = root
- emitter.sequence_context = sequence
- emitter.mapping_context = mapping
- emitter.simple_key_context = simple_key
-
- switch event.typ {
- case yaml_ALIAS_EVENT:
- return yaml_emitter_emit_alias(emitter, event)
- case yaml_SCALAR_EVENT:
- return yaml_emitter_emit_scalar(emitter, event)
- case yaml_SEQUENCE_START_EVENT:
- return yaml_emitter_emit_sequence_start(emitter, event)
- case yaml_MAPPING_START_EVENT:
- return yaml_emitter_emit_mapping_start(emitter, event)
- default:
- return yaml_emitter_set_emitter_error(emitter,
- fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
- }
-}
-
-// Expect ALIAS.
-func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
-}
-
-// Expect SCALAR.
-func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_select_scalar_style(emitter, event) {
- return false
- }
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- if !yaml_emitter_process_tag(emitter) {
- return false
- }
- if !yaml_emitter_increase_indent(emitter, true, false) {
- return false
- }
- if !yaml_emitter_process_scalar(emitter) {
- return false
- }
- emitter.indent = emitter.indents[len(emitter.indents)-1]
- emitter.indents = emitter.indents[:len(emitter.indents)-1]
- emitter.state = emitter.states[len(emitter.states)-1]
- emitter.states = emitter.states[:len(emitter.states)-1]
- return true
-}
-
-// Expect SEQUENCE-START.
-func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- if !yaml_emitter_process_tag(emitter) {
- return false
- }
- if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE ||
- yaml_emitter_check_empty_sequence(emitter) {
- emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
- } else {
- emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
- }
- return true
-}
-
-// Expect MAPPING-START.
-func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
- if !yaml_emitter_process_anchor(emitter) {
- return false
- }
- if !yaml_emitter_process_tag(emitter) {
- return false
- }
- if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE ||
- yaml_emitter_check_empty_mapping(emitter) {
- emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
- } else {
- emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
- }
- return true
-}
-
-// Check if the document content is an empty scalar.
-func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
- return false // [Go] Huh?
-}
-
-// Check if the next events represent an empty sequence.
-func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
- if len(emitter.events)-emitter.events_head < 2 {
- return false
- }
- return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT &&
- emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT
-}
-
-// Check if the next events represent an empty mapping.
-func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
- if len(emitter.events)-emitter.events_head < 2 {
- return false
- }
- return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT &&
- emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT
-}
-
-// Check if the next node can be expressed as a simple key.
-func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
- length := 0
- switch emitter.events[emitter.events_head].typ {
- case yaml_ALIAS_EVENT:
- length += len(emitter.anchor_data.anchor)
- case yaml_SCALAR_EVENT:
- if emitter.scalar_data.multiline {
- return false
- }
- length += len(emitter.anchor_data.anchor) +
- len(emitter.tag_data.handle) +
- len(emitter.tag_data.suffix) +
- len(emitter.scalar_data.value)
- case yaml_SEQUENCE_START_EVENT:
- if !yaml_emitter_check_empty_sequence(emitter) {
- return false
- }
- length += len(emitter.anchor_data.anchor) +
- len(emitter.tag_data.handle) +
- len(emitter.tag_data.suffix)
- case yaml_MAPPING_START_EVENT:
- if !yaml_emitter_check_empty_mapping(emitter) {
- return false
- }
- length += len(emitter.anchor_data.anchor) +
- len(emitter.tag_data.handle) +
- len(emitter.tag_data.suffix)
- default:
- return false
- }
- return length <= 128
-}
-
-// Determine an acceptable scalar style.
-func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-
- no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
- if no_tag && !event.implicit && !event.quoted_implicit {
- return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified")
- }
-
- style := event.scalar_style()
- if style == yaml_ANY_SCALAR_STYLE {
- style = yaml_PLAIN_SCALAR_STYLE
- }
- if emitter.canonical {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- if emitter.simple_key_context && emitter.scalar_data.multiline {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
-
- if style == yaml_PLAIN_SCALAR_STYLE {
- if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed ||
- emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed {
- style = yaml_SINGLE_QUOTED_SCALAR_STYLE
- }
- if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) {
- style = yaml_SINGLE_QUOTED_SCALAR_STYLE
- }
- if no_tag && !event.implicit {
- style = yaml_SINGLE_QUOTED_SCALAR_STYLE
- }
- }
- if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
- if !emitter.scalar_data.single_quoted_allowed {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- }
- if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
- if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context {
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- }
-
- if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE {
- emitter.tag_data.handle = []byte{'!'}
- }
- emitter.scalar_data.style = style
- return true
-}
-
-// Write an anchor.
-func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
- if emitter.anchor_data.anchor == nil {
- return true
- }
- c := []byte{'&'}
- if emitter.anchor_data.alias {
- c[0] = '*'
- }
- if !yaml_emitter_write_indicator(emitter, c, true, false, false) {
- return false
- }
- return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
-}
-
-// Write a tag.
-func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
- if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
- return true
- }
- if len(emitter.tag_data.handle) > 0 {
- if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
- return false
- }
- if len(emitter.tag_data.suffix) > 0 {
- if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
- return false
- }
- }
- } else {
- // [Go] Allocate these slices elsewhere.
- if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
- return false
- }
- if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
- return false
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) {
- return false
- }
- }
- return true
-}
-
-// Write a scalar.
-func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
- switch emitter.scalar_data.style {
- case yaml_PLAIN_SCALAR_STYLE:
- return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
- case yaml_SINGLE_QUOTED_SCALAR_STYLE:
- return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
- case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
- return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
-
- case yaml_LITERAL_SCALAR_STYLE:
- return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value)
-
- case yaml_FOLDED_SCALAR_STYLE:
- return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value)
- }
- panic("unknown scalar style")
-}
-
-// Check if a %YAML directive is valid.
-func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool {
- if version_directive.major != 1 || version_directive.minor != 1 {
- return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive")
- }
- return true
-}
-
-// Check if a %TAG directive is valid.
-func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool {
- handle := tag_directive.handle
- prefix := tag_directive.prefix
- if len(handle) == 0 {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty")
- }
- if handle[0] != '!' {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'")
- }
- if handle[len(handle)-1] != '!' {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'")
- }
- for i := 1; i < len(handle)-1; i += width(handle[i]) {
- if !is_alpha(handle, i) {
- return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only")
- }
- }
- if len(prefix) == 0 {
- return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty")
- }
- return true
-}
-
-// Check if an anchor is valid.
-func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool {
- if len(anchor) == 0 {
- problem := "anchor value must not be empty"
- if alias {
- problem = "alias value must not be empty"
- }
- return yaml_emitter_set_emitter_error(emitter, problem)
- }
- for i := 0; i < len(anchor); i += width(anchor[i]) {
- if !is_alpha(anchor, i) {
- problem := "anchor value must contain alphanumerical characters only"
- if alias {
- problem = "alias value must contain alphanumerical characters only"
- }
- return yaml_emitter_set_emitter_error(emitter, problem)
- }
- }
- emitter.anchor_data.anchor = anchor
- emitter.anchor_data.alias = alias
- return true
-}
-
-// Check if a tag is valid.
-func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
- if len(tag) == 0 {
- return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")
- }
- for i := 0; i < len(emitter.tag_directives); i++ {
- tag_directive := &emitter.tag_directives[i]
- if bytes.HasPrefix(tag, tag_directive.prefix) {
- emitter.tag_data.handle = tag_directive.handle
- emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
- return true
- }
- }
- emitter.tag_data.suffix = tag
- return true
-}
-
-// Check if a scalar is valid.
-func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
- var (
- block_indicators = false
- flow_indicators = false
- line_breaks = false
- special_characters = false
-
- leading_space = false
- leading_break = false
- trailing_space = false
- trailing_break = false
- break_space = false
- space_break = false
-
- preceded_by_whitespace = false
- followed_by_whitespace = false
- previous_space = false
- previous_break = false
- )
-
- emitter.scalar_data.value = value
-
- if len(value) == 0 {
- emitter.scalar_data.multiline = false
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = true
- emitter.scalar_data.single_quoted_allowed = true
- emitter.scalar_data.block_allowed = false
- return true
- }
-
- if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) {
- block_indicators = true
- flow_indicators = true
- }
-
- preceded_by_whitespace = true
- for i, w := 0, 0; i < len(value); i += w {
- w = width(value[i])
- followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
-
- if i == 0 {
- switch value[i] {
- case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
- flow_indicators = true
- block_indicators = true
- case '?', ':':
- flow_indicators = true
- if followed_by_whitespace {
- block_indicators = true
- }
- case '-':
- if followed_by_whitespace {
- flow_indicators = true
- block_indicators = true
- }
- }
- } else {
- switch value[i] {
- case ',', '?', '[', ']', '{', '}':
- flow_indicators = true
- case ':':
- flow_indicators = true
- if followed_by_whitespace {
- block_indicators = true
- }
- case '#':
- if preceded_by_whitespace {
- flow_indicators = true
- block_indicators = true
- }
- }
- }
-
- if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode {
- special_characters = true
- }
- if is_space(value, i) {
- if i == 0 {
- leading_space = true
- }
- if i+width(value[i]) == len(value) {
- trailing_space = true
- }
- if previous_break {
- break_space = true
- }
- previous_space = true
- previous_break = false
- } else if is_break(value, i) {
- line_breaks = true
- if i == 0 {
- leading_break = true
- }
- if i+width(value[i]) == len(value) {
- trailing_break = true
- }
- if previous_space {
- space_break = true
- }
- previous_space = false
- previous_break = true
- } else {
- previous_space = false
- previous_break = false
- }
-
- // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
- preceded_by_whitespace = is_blankz(value, i)
- }
-
- emitter.scalar_data.multiline = line_breaks
- emitter.scalar_data.flow_plain_allowed = true
- emitter.scalar_data.block_plain_allowed = true
- emitter.scalar_data.single_quoted_allowed = true
- emitter.scalar_data.block_allowed = true
-
- if leading_space || leading_break || trailing_space || trailing_break {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- }
- if trailing_space {
- emitter.scalar_data.block_allowed = false
- }
- if break_space {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- emitter.scalar_data.single_quoted_allowed = false
- }
- if space_break || special_characters {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- emitter.scalar_data.single_quoted_allowed = false
- emitter.scalar_data.block_allowed = false
- }
- if line_breaks {
- emitter.scalar_data.flow_plain_allowed = false
- emitter.scalar_data.block_plain_allowed = false
- }
- if flow_indicators {
- emitter.scalar_data.flow_plain_allowed = false
- }
- if block_indicators {
- emitter.scalar_data.block_plain_allowed = false
- }
- return true
-}
-
-// Check if the event data is valid.
-func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
-
- emitter.anchor_data.anchor = nil
- emitter.tag_data.handle = nil
- emitter.tag_data.suffix = nil
- emitter.scalar_data.value = nil
-
- switch event.typ {
- case yaml_ALIAS_EVENT:
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) {
- return false
- }
-
- case yaml_SCALAR_EVENT:
- if len(event.anchor) > 0 {
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
- return false
- }
- }
- if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) {
- if !yaml_emitter_analyze_tag(emitter, event.tag) {
- return false
- }
- }
- if !yaml_emitter_analyze_scalar(emitter, event.value) {
- return false
- }
-
- case yaml_SEQUENCE_START_EVENT:
- if len(event.anchor) > 0 {
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
- return false
- }
- }
- if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
- if !yaml_emitter_analyze_tag(emitter, event.tag) {
- return false
- }
- }
-
- case yaml_MAPPING_START_EVENT:
- if len(event.anchor) > 0 {
- if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
- return false
- }
- }
- if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
- if !yaml_emitter_analyze_tag(emitter, event.tag) {
- return false
- }
- }
- }
- return true
-}
-
-// Write the BOM character.
-func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
- if !flush(emitter) {
- return false
- }
- pos := emitter.buffer_pos
- emitter.buffer[pos+0] = '\xEF'
- emitter.buffer[pos+1] = '\xBB'
- emitter.buffer[pos+2] = '\xBF'
- emitter.buffer_pos += 3
- return true
-}
-
-func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
- indent := emitter.indent
- if indent < 0 {
- indent = 0
- }
- if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) {
- if !put_break(emitter) {
- return false
- }
- }
- for emitter.column < indent {
- if !put(emitter, ' ') {
- return false
- }
- }
- emitter.whitespace = true
- emitter.indention = true
- return true
-}
-
-func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool {
- if need_whitespace && !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
- if !write_all(emitter, indicator) {
- return false
- }
- emitter.whitespace = is_whitespace
- emitter.indention = (emitter.indention && is_indention)
- emitter.open_ended = false
- return true
-}
-
-func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
- if !write_all(emitter, value) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
- if !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
- if !write_all(emitter, value) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool {
- if need_whitespace && !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
- for i := 0; i < len(value); {
- var must_write bool
- switch value[i] {
- case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']':
- must_write = true
- default:
- must_write = is_alpha(value, i)
- }
- if must_write {
- if !write(emitter, value, &i) {
- return false
- }
- } else {
- w := width(value[i])
- for k := 0; k < w; k++ {
- octet := value[i]
- i++
- if !put(emitter, '%') {
- return false
- }
-
- c := octet >> 4
- if c < 10 {
- c += '0'
- } else {
- c += 'A' - 10
- }
- if !put(emitter, c) {
- return false
- }
-
- c = octet & 0x0f
- if c < 10 {
- c += '0'
- } else {
- c += 'A' - 10
- }
- if !put(emitter, c) {
- return false
- }
- }
- }
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
- if !emitter.whitespace {
- if !put(emitter, ' ') {
- return false
- }
- }
-
- spaces := false
- breaks := false
- for i := 0; i < len(value); {
- if is_space(value, i) {
- if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- i += width(value[i])
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- }
- spaces = true
- } else if is_break(value, i) {
- if !breaks && value[i] == '\n' {
- if !put_break(emitter) {
- return false
- }
- }
- if !write_break(emitter, value, &i) {
- return false
- }
- emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !write(emitter, value, &i) {
- return false
- }
- emitter.indention = false
- spaces = false
- breaks = false
- }
- }
-
- emitter.whitespace = false
- emitter.indention = false
- if emitter.root_context {
- emitter.open_ended = true
- }
-
- return true
-}
-
-func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
-
- if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) {
- return false
- }
-
- spaces := false
- breaks := false
- for i := 0; i < len(value); {
- if is_space(value, i) {
- if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- i += width(value[i])
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- }
- spaces = true
- } else if is_break(value, i) {
- if !breaks && value[i] == '\n' {
- if !put_break(emitter) {
- return false
- }
- }
- if !write_break(emitter, value, &i) {
- return false
- }
- emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if value[i] == '\'' {
- if !put(emitter, '\'') {
- return false
- }
- }
- if !write(emitter, value, &i) {
- return false
- }
- emitter.indention = false
- spaces = false
- breaks = false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
- spaces := false
- if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) {
- return false
- }
-
- for i := 0; i < len(value); {
- if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) ||
- is_bom(value, i) || is_break(value, i) ||
- value[i] == '"' || value[i] == '\\' {
-
- octet := value[i]
-
- var w int
- var v rune
- switch {
- case octet&0x80 == 0x00:
- w, v = 1, rune(octet&0x7F)
- case octet&0xE0 == 0xC0:
- w, v = 2, rune(octet&0x1F)
- case octet&0xF0 == 0xE0:
- w, v = 3, rune(octet&0x0F)
- case octet&0xF8 == 0xF0:
- w, v = 4, rune(octet&0x07)
- }
- for k := 1; k < w; k++ {
- octet = value[i+k]
- v = (v << 6) + (rune(octet) & 0x3F)
- }
- i += w
-
- if !put(emitter, '\\') {
- return false
- }
-
- var ok bool
- switch v {
- case 0x00:
- ok = put(emitter, '0')
- case 0x07:
- ok = put(emitter, 'a')
- case 0x08:
- ok = put(emitter, 'b')
- case 0x09:
- ok = put(emitter, 't')
- case 0x0A:
- ok = put(emitter, 'n')
- case 0x0b:
- ok = put(emitter, 'v')
- case 0x0c:
- ok = put(emitter, 'f')
- case 0x0d:
- ok = put(emitter, 'r')
- case 0x1b:
- ok = put(emitter, 'e')
- case 0x22:
- ok = put(emitter, '"')
- case 0x5c:
- ok = put(emitter, '\\')
- case 0x85:
- ok = put(emitter, 'N')
- case 0xA0:
- ok = put(emitter, '_')
- case 0x2028:
- ok = put(emitter, 'L')
- case 0x2029:
- ok = put(emitter, 'P')
- default:
- if v <= 0xFF {
- ok = put(emitter, 'x')
- w = 2
- } else if v <= 0xFFFF {
- ok = put(emitter, 'u')
- w = 4
- } else {
- ok = put(emitter, 'U')
- w = 8
- }
- for k := (w - 1) * 4; ok && k >= 0; k -= 4 {
- digit := byte((v >> uint(k)) & 0x0F)
- if digit < 10 {
- ok = put(emitter, digit+'0')
- } else {
- ok = put(emitter, digit+'A'-10)
- }
- }
- }
- if !ok {
- return false
- }
- spaces = false
- } else if is_space(value, i) {
- if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- if is_space(value, i+1) {
- if !put(emitter, '\\') {
- return false
- }
- }
- i += width(value[i])
- } else if !write(emitter, value, &i) {
- return false
- }
- spaces = true
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- spaces = false
- }
- }
- if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) {
- return false
- }
- emitter.whitespace = false
- emitter.indention = false
- return true
-}
-
-func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
- if is_space(value, 0) || is_break(value, 0) {
- indent_hint := []byte{'0' + byte(emitter.best_indent)}
- if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
- return false
- }
- }
-
- emitter.open_ended = false
-
- var chomp_hint [1]byte
- if len(value) == 0 {
- chomp_hint[0] = '-'
- } else {
- i := len(value) - 1
- for value[i]&0xC0 == 0x80 {
- i--
- }
- if !is_break(value, i) {
- chomp_hint[0] = '-'
- } else if i == 0 {
- chomp_hint[0] = '+'
- emitter.open_ended = true
- } else {
- i--
- for value[i]&0xC0 == 0x80 {
- i--
- }
- if is_break(value, i) {
- chomp_hint[0] = '+'
- emitter.open_ended = true
- }
- }
- }
- if chomp_hint[0] != 0 {
- if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
- return false
- }
- }
- return true
-}
-
-func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
- if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) {
- return false
- }
- if !yaml_emitter_write_block_scalar_hints(emitter, value) {
- return false
- }
- if !put_break(emitter) {
- return false
- }
- emitter.indention = true
- emitter.whitespace = true
- breaks := true
- for i := 0; i < len(value); {
- if is_break(value, i) {
- if !write_break(emitter, value, &i) {
- return false
- }
- emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- }
- if !write(emitter, value, &i) {
- return false
- }
- emitter.indention = false
- breaks = false
- }
- }
-
- return true
-}
-
-func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
- if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) {
- return false
- }
- if !yaml_emitter_write_block_scalar_hints(emitter, value) {
- return false
- }
-
- if !put_break(emitter) {
- return false
- }
- emitter.indention = true
- emitter.whitespace = true
-
- breaks := true
- leading_spaces := true
- for i := 0; i < len(value); {
- if is_break(value, i) {
- if !breaks && !leading_spaces && value[i] == '\n' {
- k := 0
- for is_break(value, k) {
- k += width(value[k])
- }
- if !is_blankz(value, k) {
- if !put_break(emitter) {
- return false
- }
- }
- }
- if !write_break(emitter, value, &i) {
- return false
- }
- emitter.indention = true
- breaks = true
- } else {
- if breaks {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- leading_spaces = is_blank(value, i)
- }
- if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width {
- if !yaml_emitter_write_indent(emitter) {
- return false
- }
- i += width(value[i])
- } else {
- if !write(emitter, value, &i) {
- return false
- }
- }
- emitter.indention = false
- breaks = false
- }
- }
- return true
-}
diff --git a/vendor/go.yaml.in/yaml/v2/encode.go b/vendor/go.yaml.in/yaml/v2/encode.go
deleted file mode 100644
index 0ee738e11b..0000000000
--- a/vendor/go.yaml.in/yaml/v2/encode.go
+++ /dev/null
@@ -1,390 +0,0 @@
-package yaml
-
-import (
- "encoding"
- "fmt"
- "io"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "time"
- "unicode/utf8"
-)
-
-// jsonNumber is the interface of the encoding/json.Number datatype.
-// Repeating the interface here avoids a dependency on encoding/json, and also
-// supports other libraries like jsoniter, which use a similar datatype with
-// the same interface. Detecting this interface is useful when dealing with
-// structures containing json.Number, which is a string under the hood. The
-// encoder should prefer the use of Int64(), Float64() and string(), in that
-// order, when encoding this type.
-type jsonNumber interface {
- Float64() (float64, error)
- Int64() (int64, error)
- String() string
-}
-
-type encoder struct {
- emitter yaml_emitter_t
- event yaml_event_t
- out []byte
- flow bool
- // doneInit holds whether the initial stream_start_event has been
- // emitted.
- doneInit bool
-}
-
-func newEncoder() *encoder {
- e := &encoder{}
- yaml_emitter_initialize(&e.emitter)
- yaml_emitter_set_output_string(&e.emitter, &e.out)
- yaml_emitter_set_unicode(&e.emitter, true)
- return e
-}
-
-func newEncoderWithWriter(w io.Writer) *encoder {
- e := &encoder{}
- yaml_emitter_initialize(&e.emitter)
- yaml_emitter_set_output_writer(&e.emitter, w)
- yaml_emitter_set_unicode(&e.emitter, true)
- return e
-}
-
-func (e *encoder) init() {
- if e.doneInit {
- return
- }
- yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
- e.emit()
- e.doneInit = true
-}
-
-func (e *encoder) finish() {
- e.emitter.open_ended = false
- yaml_stream_end_event_initialize(&e.event)
- e.emit()
-}
-
-func (e *encoder) destroy() {
- yaml_emitter_delete(&e.emitter)
-}
-
-func (e *encoder) emit() {
- // This will internally delete the e.event value.
- e.must(yaml_emitter_emit(&e.emitter, &e.event))
-}
-
-func (e *encoder) must(ok bool) {
- if !ok {
- msg := e.emitter.problem
- if msg == "" {
- msg = "unknown problem generating YAML content"
- }
- failf("%s", msg)
- }
-}
-
-func (e *encoder) marshalDoc(tag string, in reflect.Value) {
- e.init()
- yaml_document_start_event_initialize(&e.event, nil, nil, true)
- e.emit()
- e.marshal(tag, in)
- yaml_document_end_event_initialize(&e.event, true)
- e.emit()
-}
-
-func (e *encoder) marshal(tag string, in reflect.Value) {
- if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
- e.nilv()
- return
- }
- iface := in.Interface()
- switch m := iface.(type) {
- case jsonNumber:
- integer, err := m.Int64()
- if err == nil {
- // In this case the json.Number is a valid int64
- in = reflect.ValueOf(integer)
- break
- }
- float, err := m.Float64()
- if err == nil {
- // In this case the json.Number is a valid float64
- in = reflect.ValueOf(float)
- break
- }
- // fallback case - no number could be obtained
- in = reflect.ValueOf(m.String())
- case time.Time, *time.Time:
- // Although time.Time implements TextMarshaler,
- // we don't want to treat it as a string for YAML
- // purposes because YAML has special support for
- // timestamps.
- case Marshaler:
- v, err := m.MarshalYAML()
- if err != nil {
- fail(err)
- }
- if v == nil {
- e.nilv()
- return
- }
- in = reflect.ValueOf(v)
- case encoding.TextMarshaler:
- text, err := m.MarshalText()
- if err != nil {
- fail(err)
- }
- in = reflect.ValueOf(string(text))
- case nil:
- e.nilv()
- return
- }
- switch in.Kind() {
- case reflect.Interface:
- e.marshal(tag, in.Elem())
- case reflect.Map:
- e.mapv(tag, in)
- case reflect.Ptr:
- if in.Type() == ptrTimeType {
- e.timev(tag, in.Elem())
- } else {
- e.marshal(tag, in.Elem())
- }
- case reflect.Struct:
- if in.Type() == timeType {
- e.timev(tag, in)
- } else {
- e.structv(tag, in)
- }
- case reflect.Slice, reflect.Array:
- if in.Type().Elem() == mapItemType {
- e.itemsv(tag, in)
- } else {
- e.slicev(tag, in)
- }
- case reflect.String:
- e.stringv(tag, in)
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if in.Type() == durationType {
- e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String()))
- } else {
- e.intv(tag, in)
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- e.uintv(tag, in)
- case reflect.Float32, reflect.Float64:
- e.floatv(tag, in)
- case reflect.Bool:
- e.boolv(tag, in)
- default:
- panic("cannot marshal type: " + in.Type().String())
- }
-}
-
-func (e *encoder) mapv(tag string, in reflect.Value) {
- e.mappingv(tag, func() {
- keys := keyList(in.MapKeys())
- sort.Sort(keys)
- for _, k := range keys {
- e.marshal("", k)
- e.marshal("", in.MapIndex(k))
- }
- })
-}
-
-func (e *encoder) itemsv(tag string, in reflect.Value) {
- e.mappingv(tag, func() {
- slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem)
- for _, item := range slice {
- e.marshal("", reflect.ValueOf(item.Key))
- e.marshal("", reflect.ValueOf(item.Value))
- }
- })
-}
-
-func (e *encoder) structv(tag string, in reflect.Value) {
- sinfo, err := getStructInfo(in.Type())
- if err != nil {
- panic(err)
- }
- e.mappingv(tag, func() {
- for _, info := range sinfo.FieldsList {
- var value reflect.Value
- if info.Inline == nil {
- value = in.Field(info.Num)
- } else {
- value = in.FieldByIndex(info.Inline)
- }
- if info.OmitEmpty && isZero(value) {
- continue
- }
- e.marshal("", reflect.ValueOf(info.Key))
- e.flow = info.Flow
- e.marshal("", value)
- }
- if sinfo.InlineMap >= 0 {
- m := in.Field(sinfo.InlineMap)
- if m.Len() > 0 {
- e.flow = false
- keys := keyList(m.MapKeys())
- sort.Sort(keys)
- for _, k := range keys {
- if _, found := sinfo.FieldsMap[k.String()]; found {
- panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String()))
- }
- e.marshal("", k)
- e.flow = false
- e.marshal("", m.MapIndex(k))
- }
- }
- }
- })
-}
-
-func (e *encoder) mappingv(tag string, f func()) {
- implicit := tag == ""
- style := yaml_BLOCK_MAPPING_STYLE
- if e.flow {
- e.flow = false
- style = yaml_FLOW_MAPPING_STYLE
- }
- yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
- e.emit()
- f()
- yaml_mapping_end_event_initialize(&e.event)
- e.emit()
-}
-
-func (e *encoder) slicev(tag string, in reflect.Value) {
- implicit := tag == ""
- style := yaml_BLOCK_SEQUENCE_STYLE
- if e.flow {
- e.flow = false
- style = yaml_FLOW_SEQUENCE_STYLE
- }
- e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
- e.emit()
- n := in.Len()
- for i := 0; i < n; i++ {
- e.marshal("", in.Index(i))
- }
- e.must(yaml_sequence_end_event_initialize(&e.event))
- e.emit()
-}
-
-// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
-//
-// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
-// in YAML 1.2 and by this package, but these should be marshalled quoted for
-// the time being for compatibility with other parsers.
-func isBase60Float(s string) (result bool) {
- // Fast path.
- if s == "" {
- return false
- }
- c := s[0]
- if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
- return false
- }
- // Do the full match.
- return base60float.MatchString(s)
-}
-
-// From http://yaml.org/type/float.html, except the regular expression there
-// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
-var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
-
-func (e *encoder) stringv(tag string, in reflect.Value) {
- var style yaml_scalar_style_t
- s := in.String()
- canUsePlain := true
- switch {
- case !utf8.ValidString(s):
- if tag == yaml_BINARY_TAG {
- failf("explicitly tagged !!binary data must be base64-encoded")
- }
- if tag != "" {
- failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
- }
- // It can't be encoded directly as YAML so use a binary tag
- // and encode it as base64.
- tag = yaml_BINARY_TAG
- s = encodeBase64(s)
- case tag == "":
- // Check to see if it would resolve to a specific
- // tag when encoded unquoted. If it doesn't,
- // there's no need to quote it.
- rtag, _ := resolve("", s)
- canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s)
- }
- // Note: it's possible for user code to emit invalid YAML
- // if they explicitly specify a tag and a string containing
- // text that's incompatible with that tag.
- switch {
- case strings.Contains(s, "\n"):
- style = yaml_LITERAL_SCALAR_STYLE
- case canUsePlain:
- style = yaml_PLAIN_SCALAR_STYLE
- default:
- style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- e.emitScalar(s, "", tag, style)
-}
-
-func (e *encoder) boolv(tag string, in reflect.Value) {
- var s string
- if in.Bool() {
- s = "true"
- } else {
- s = "false"
- }
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
-}
-
-func (e *encoder) intv(tag string, in reflect.Value) {
- s := strconv.FormatInt(in.Int(), 10)
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
-}
-
-func (e *encoder) uintv(tag string, in reflect.Value) {
- s := strconv.FormatUint(in.Uint(), 10)
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
-}
-
-func (e *encoder) timev(tag string, in reflect.Value) {
- t := in.Interface().(time.Time)
- s := t.Format(time.RFC3339Nano)
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
-}
-
-func (e *encoder) floatv(tag string, in reflect.Value) {
- // Issue #352: When formatting, use the precision of the underlying value
- precision := 64
- if in.Kind() == reflect.Float32 {
- precision = 32
- }
-
- s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
- switch s {
- case "+Inf":
- s = ".inf"
- case "-Inf":
- s = "-.inf"
- case "NaN":
- s = ".nan"
- }
- e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
-}
-
-func (e *encoder) nilv() {
- e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE)
-}
-
-func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) {
- implicit := tag == ""
- e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
- e.emit()
-}
diff --git a/vendor/go.yaml.in/yaml/v2/parserc.go b/vendor/go.yaml.in/yaml/v2/parserc.go
deleted file mode 100644
index 81d05dfe57..0000000000
--- a/vendor/go.yaml.in/yaml/v2/parserc.go
+++ /dev/null
@@ -1,1095 +0,0 @@
-package yaml
-
-import (
- "bytes"
-)
-
-// The parser implements the following grammar:
-//
-// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
-// implicit_document ::= block_node DOCUMENT-END*
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-// block_node_or_indentless_sequence ::=
-// ALIAS
-// | properties (block_content | indentless_block_sequence)?
-// | block_content
-// | indentless_block_sequence
-// block_node ::= ALIAS
-// | properties block_content?
-// | block_content
-// flow_node ::= ALIAS
-// | properties flow_content?
-// | flow_content
-// properties ::= TAG ANCHOR? | ANCHOR TAG?
-// block_content ::= block_collection | flow_collection | SCALAR
-// flow_content ::= flow_collection | SCALAR
-// block_collection ::= block_sequence | block_mapping
-// flow_collection ::= flow_sequence | flow_mapping
-// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
-// block_mapping ::= BLOCK-MAPPING_START
-// ((KEY block_node_or_indentless_sequence?)?
-// (VALUE block_node_or_indentless_sequence?)?)*
-// BLOCK-END
-// flow_sequence ::= FLOW-SEQUENCE-START
-// (flow_sequence_entry FLOW-ENTRY)*
-// flow_sequence_entry?
-// FLOW-SEQUENCE-END
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// flow_mapping ::= FLOW-MAPPING-START
-// (flow_mapping_entry FLOW-ENTRY)*
-// flow_mapping_entry?
-// FLOW-MAPPING-END
-// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-
-// Peek the next token in the token queue.
-func peek_token(parser *yaml_parser_t) *yaml_token_t {
- if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
- return &parser.tokens[parser.tokens_head]
- }
- return nil
-}
-
-// Remove the next token from the queue (must be called after peek_token).
-func skip_token(parser *yaml_parser_t) {
- parser.token_available = false
- parser.tokens_parsed++
- parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN
- parser.tokens_head++
-}
-
-// Get the next event.
-func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
- // Erase the event object.
- *event = yaml_event_t{}
-
- // No events after the end of the stream or error.
- if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {
- return true
- }
-
- // Generate the next event.
- return yaml_parser_state_machine(parser, event)
-}
-
-// Set parser error.
-func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {
- parser.error = yaml_PARSER_ERROR
- parser.problem = problem
- parser.problem_mark = problem_mark
- return false
-}
-
-func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {
- parser.error = yaml_PARSER_ERROR
- parser.context = context
- parser.context_mark = context_mark
- parser.problem = problem
- parser.problem_mark = problem_mark
- return false
-}
-
-// State dispatcher.
-func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
- //trace("yaml_parser_state_machine", "state:", parser.state.String())
-
- switch parser.state {
- case yaml_PARSE_STREAM_START_STATE:
- return yaml_parser_parse_stream_start(parser, event)
-
- case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
- return yaml_parser_parse_document_start(parser, event, true)
-
- case yaml_PARSE_DOCUMENT_START_STATE:
- return yaml_parser_parse_document_start(parser, event, false)
-
- case yaml_PARSE_DOCUMENT_CONTENT_STATE:
- return yaml_parser_parse_document_content(parser, event)
-
- case yaml_PARSE_DOCUMENT_END_STATE:
- return yaml_parser_parse_document_end(parser, event)
-
- case yaml_PARSE_BLOCK_NODE_STATE:
- return yaml_parser_parse_node(parser, event, true, false)
-
- case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
- return yaml_parser_parse_node(parser, event, true, true)
-
- case yaml_PARSE_FLOW_NODE_STATE:
- return yaml_parser_parse_node(parser, event, false, false)
-
- case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
- return yaml_parser_parse_block_sequence_entry(parser, event, true)
-
- case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
- return yaml_parser_parse_block_sequence_entry(parser, event, false)
-
- case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
- return yaml_parser_parse_indentless_sequence_entry(parser, event)
-
- case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
- return yaml_parser_parse_block_mapping_key(parser, event, true)
-
- case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
- return yaml_parser_parse_block_mapping_key(parser, event, false)
-
- case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
- return yaml_parser_parse_block_mapping_value(parser, event)
-
- case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
- return yaml_parser_parse_flow_sequence_entry(parser, event, true)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
- return yaml_parser_parse_flow_sequence_entry(parser, event, false)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
- return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
- return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
-
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
- return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
-
- case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
- return yaml_parser_parse_flow_mapping_key(parser, event, true)
-
- case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
- return yaml_parser_parse_flow_mapping_key(parser, event, false)
-
- case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
- return yaml_parser_parse_flow_mapping_value(parser, event, false)
-
- case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
- return yaml_parser_parse_flow_mapping_value(parser, event, true)
-
- default:
- panic("invalid parser state")
- }
-}
-
-// Parse the production:
-// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
-// ************
-func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_STREAM_START_TOKEN {
- return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark)
- }
- parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
- *event = yaml_event_t{
- typ: yaml_STREAM_START_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- encoding: token.encoding,
- }
- skip_token(parser)
- return true
-}
-
-// Parse the productions:
-// implicit_document ::= block_node DOCUMENT-END*
-// *
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-// *************************
-func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- // Parse extra document end indicators.
- if !implicit {
- for token.typ == yaml_DOCUMENT_END_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
- }
-
- if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&
- token.typ != yaml_TAG_DIRECTIVE_TOKEN &&
- token.typ != yaml_DOCUMENT_START_TOKEN &&
- token.typ != yaml_STREAM_END_TOKEN {
- // Parse an implicit document.
- if !yaml_parser_process_directives(parser, nil, nil) {
- return false
- }
- parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
- parser.state = yaml_PARSE_BLOCK_NODE_STATE
-
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_START_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
-
- } else if token.typ != yaml_STREAM_END_TOKEN {
- // Parse an explicit document.
- var version_directive *yaml_version_directive_t
- var tag_directives []yaml_tag_directive_t
- start_mark := token.start_mark
- if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {
- return false
- }
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_DOCUMENT_START_TOKEN {
- yaml_parser_set_parser_error(parser,
- "did not find expected ", token.start_mark)
- return false
- }
- parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
- parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
- end_mark := token.end_mark
-
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- version_directive: version_directive,
- tag_directives: tag_directives,
- implicit: false,
- }
- skip_token(parser)
-
- } else {
- // Parse the stream end.
- parser.state = yaml_PARSE_END_STATE
- *event = yaml_event_t{
- typ: yaml_STREAM_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
- skip_token(parser)
- }
-
- return true
-}
-
-// Parse the productions:
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-// ***********
-//
-func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||
- token.typ == yaml_TAG_DIRECTIVE_TOKEN ||
- token.typ == yaml_DOCUMENT_START_TOKEN ||
- token.typ == yaml_DOCUMENT_END_TOKEN ||
- token.typ == yaml_STREAM_END_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- return yaml_parser_process_empty_scalar(parser, event,
- token.start_mark)
- }
- return yaml_parser_parse_node(parser, event, true, false)
-}
-
-// Parse the productions:
-// implicit_document ::= block_node DOCUMENT-END*
-// *************
-// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
-//
-func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- start_mark := token.start_mark
- end_mark := token.start_mark
-
- implicit := true
- if token.typ == yaml_DOCUMENT_END_TOKEN {
- end_mark = token.end_mark
- skip_token(parser)
- implicit = false
- }
-
- parser.tag_directives = parser.tag_directives[:0]
-
- parser.state = yaml_PARSE_DOCUMENT_START_STATE
- *event = yaml_event_t{
- typ: yaml_DOCUMENT_END_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- implicit: implicit,
- }
- return true
-}
-
-// Parse the productions:
-// block_node_or_indentless_sequence ::=
-// ALIAS
-// *****
-// | properties (block_content | indentless_block_sequence)?
-// ********** *
-// | block_content | indentless_block_sequence
-// *
-// block_node ::= ALIAS
-// *****
-// | properties block_content?
-// ********** *
-// | block_content
-// *
-// flow_node ::= ALIAS
-// *****
-// | properties flow_content?
-// ********** *
-// | flow_content
-// *
-// properties ::= TAG ANCHOR? | ANCHOR TAG?
-// *************************
-// block_content ::= block_collection | flow_collection | SCALAR
-// ******
-// flow_content ::= flow_collection | SCALAR
-// ******
-func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
- //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_ALIAS_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- *event = yaml_event_t{
- typ: yaml_ALIAS_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- anchor: token.value,
- }
- skip_token(parser)
- return true
- }
-
- start_mark := token.start_mark
- end_mark := token.start_mark
-
- var tag_token bool
- var tag_handle, tag_suffix, anchor []byte
- var tag_mark yaml_mark_t
- if token.typ == yaml_ANCHOR_TOKEN {
- anchor = token.value
- start_mark = token.start_mark
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_TAG_TOKEN {
- tag_token = true
- tag_handle = token.value
- tag_suffix = token.suffix
- tag_mark = token.start_mark
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
- } else if token.typ == yaml_TAG_TOKEN {
- tag_token = true
- tag_handle = token.value
- tag_suffix = token.suffix
- start_mark = token.start_mark
- tag_mark = token.start_mark
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_ANCHOR_TOKEN {
- anchor = token.value
- end_mark = token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
- }
-
- var tag []byte
- if tag_token {
- if len(tag_handle) == 0 {
- tag = tag_suffix
- tag_suffix = nil
- } else {
- for i := range parser.tag_directives {
- if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {
- tag = append([]byte(nil), parser.tag_directives[i].prefix...)
- tag = append(tag, tag_suffix...)
- break
- }
- }
- if len(tag) == 0 {
- yaml_parser_set_parser_error_context(parser,
- "while parsing a node", start_mark,
- "found undefined tag handle", tag_mark)
- return false
- }
- }
- }
-
- implicit := len(tag) == 0
- if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
- }
- return true
- }
- if token.typ == yaml_SCALAR_TOKEN {
- var plain_implicit, quoted_implicit bool
- end_mark = token.end_mark
- if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {
- plain_implicit = true
- } else if len(tag) == 0 {
- quoted_implicit = true
- }
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
-
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- value: token.value,
- implicit: plain_implicit,
- quoted_implicit: quoted_implicit,
- style: yaml_style_t(token.style),
- }
- skip_token(parser)
- return true
- }
- if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {
- // [Go] Some of the events below can be merged as they differ only on style.
- end_mark = token.end_mark
- parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),
- }
- return true
- }
- if token.typ == yaml_FLOW_MAPPING_START_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),
- }
- return true
- }
- if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
- }
- return true
- }
- if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {
- end_mark = token.end_mark
- parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
- }
- return true
- }
- if len(anchor) > 0 || len(tag) > 0 {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
-
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- start_mark: start_mark,
- end_mark: end_mark,
- anchor: anchor,
- tag: tag,
- implicit: implicit,
- quoted_implicit: false,
- style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
- }
- return true
- }
-
- context := "while parsing a flow node"
- if block {
- context = "while parsing a block node"
- }
- yaml_parser_set_parser_error_context(parser, context, start_mark,
- "did not find expected node content", token.start_mark)
- return false
-}
-
-// Parse the productions:
-// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
-// ******************** *********** * *********
-//
-func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_BLOCK_ENTRY_TOKEN {
- mark := token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
- return yaml_parser_parse_node(parser, event, true, false)
- } else {
- parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- }
- if token.typ == yaml_BLOCK_END_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
-
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
-
- skip_token(parser)
- return true
- }
-
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a block collection", context_mark,
- "did not find expected '-' indicator", token.start_mark)
-}
-
-// Parse the productions:
-// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
-// *********** *
-func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_BLOCK_ENTRY_TOKEN {
- mark := token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_BLOCK_ENTRY_TOKEN &&
- token.typ != yaml_KEY_TOKEN &&
- token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
- return yaml_parser_parse_node(parser, event, true, false)
- }
- parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
-
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark?
- }
- return true
-}
-
-// Parse the productions:
-// block_mapping ::= BLOCK-MAPPING_START
-// *******************
-// ((KEY block_node_or_indentless_sequence?)?
-// *** *
-// (VALUE block_node_or_indentless_sequence?)?)*
-//
-// BLOCK-END
-// *********
-//
-func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ == yaml_KEY_TOKEN {
- mark := token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_KEY_TOKEN &&
- token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, true, true)
- } else {
- parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- } else if token.typ == yaml_BLOCK_END_TOKEN {
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
- skip_token(parser)
- return true
- }
-
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a block mapping", context_mark,
- "did not find expected key", token.start_mark)
-}
-
-// Parse the productions:
-// block_mapping ::= BLOCK-MAPPING_START
-//
-// ((KEY block_node_or_indentless_sequence?)?
-//
-// (VALUE block_node_or_indentless_sequence?)?)*
-// ***** *
-// BLOCK-END
-//
-//
-func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_VALUE_TOKEN {
- mark := token.end_mark
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_KEY_TOKEN &&
- token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_BLOCK_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
- return yaml_parser_parse_node(parser, event, true, true)
- }
- parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
- }
- parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Parse the productions:
-// flow_sequence ::= FLOW-SEQUENCE-START
-// *******************
-// (flow_sequence_entry FLOW-ENTRY)*
-// * **********
-// flow_sequence_entry?
-// *
-// FLOW-SEQUENCE-END
-// *****************
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// *
-//
-func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- if !first {
- if token.typ == yaml_FLOW_ENTRY_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- } else {
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a flow sequence", context_mark,
- "did not find expected ',' or ']'", token.start_mark)
- }
- }
-
- if token.typ == yaml_KEY_TOKEN {
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_START_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- implicit: true,
- style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),
- }
- skip_token(parser)
- return true
- } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
-
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
-
- *event = yaml_event_t{
- typ: yaml_SEQUENCE_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
-
- skip_token(parser)
- return true
-}
-
-//
-// Parse the productions:
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// *** *
-//
-func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_FLOW_ENTRY_TOKEN &&
- token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- mark := token.end_mark
- skip_token(parser)
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
- return yaml_parser_process_empty_scalar(parser, event, mark)
-}
-
-// Parse the productions:
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// ***** *
-//
-func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ == yaml_VALUE_TOKEN {
- skip_token(parser)
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Parse the productions:
-// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// *
-//
-func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.start_mark, // [Go] Shouldn't this be end_mark?
- }
- return true
-}
-
-// Parse the productions:
-// flow_mapping ::= FLOW-MAPPING-START
-// ******************
-// (flow_mapping_entry FLOW-ENTRY)*
-// * **********
-// flow_mapping_entry?
-// ******************
-// FLOW-MAPPING-END
-// ****************
-// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// * *** *
-//
-func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
- if first {
- token := peek_token(parser)
- parser.marks = append(parser.marks, token.start_mark)
- skip_token(parser)
- }
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- if !first {
- if token.typ == yaml_FLOW_ENTRY_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- } else {
- context_mark := parser.marks[len(parser.marks)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- return yaml_parser_set_parser_error_context(parser,
- "while parsing a flow mapping", context_mark,
- "did not find expected ',' or '}'", token.start_mark)
- }
- }
-
- if token.typ == yaml_KEY_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_VALUE_TOKEN &&
- token.typ != yaml_FLOW_ENTRY_TOKEN &&
- token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- } else {
- parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
- }
- } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
-
- parser.state = parser.states[len(parser.states)-1]
- parser.states = parser.states[:len(parser.states)-1]
- parser.marks = parser.marks[:len(parser.marks)-1]
- *event = yaml_event_t{
- typ: yaml_MAPPING_END_EVENT,
- start_mark: token.start_mark,
- end_mark: token.end_mark,
- }
- skip_token(parser)
- return true
-}
-
-// Parse the productions:
-// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-// * ***** *
-//
-func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
- token := peek_token(parser)
- if token == nil {
- return false
- }
- if empty {
- parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
- }
- if token.typ == yaml_VALUE_TOKEN {
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {
- parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
- return yaml_parser_parse_node(parser, event, false, false)
- }
- }
- parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
- return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
-}
-
-// Generate an empty scalar event.
-func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {
- *event = yaml_event_t{
- typ: yaml_SCALAR_EVENT,
- start_mark: mark,
- end_mark: mark,
- value: nil, // Empty
- implicit: true,
- style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
- }
- return true
-}
-
-var default_tag_directives = []yaml_tag_directive_t{
- {[]byte("!"), []byte("!")},
- {[]byte("!!"), []byte("tag:yaml.org,2002:")},
-}
-
-// Parse directives.
-func yaml_parser_process_directives(parser *yaml_parser_t,
- version_directive_ref **yaml_version_directive_t,
- tag_directives_ref *[]yaml_tag_directive_t) bool {
-
- var version_directive *yaml_version_directive_t
- var tag_directives []yaml_tag_directive_t
-
- token := peek_token(parser)
- if token == nil {
- return false
- }
-
- for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {
- if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {
- if version_directive != nil {
- yaml_parser_set_parser_error(parser,
- "found duplicate %YAML directive", token.start_mark)
- return false
- }
- if token.major != 1 || token.minor != 1 {
- yaml_parser_set_parser_error(parser,
- "found incompatible YAML document", token.start_mark)
- return false
- }
- version_directive = &yaml_version_directive_t{
- major: token.major,
- minor: token.minor,
- }
- } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {
- value := yaml_tag_directive_t{
- handle: token.value,
- prefix: token.prefix,
- }
- if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {
- return false
- }
- tag_directives = append(tag_directives, value)
- }
-
- skip_token(parser)
- token = peek_token(parser)
- if token == nil {
- return false
- }
- }
-
- for i := range default_tag_directives {
- if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
- return false
- }
- }
-
- if version_directive_ref != nil {
- *version_directive_ref = version_directive
- }
- if tag_directives_ref != nil {
- *tag_directives_ref = tag_directives
- }
- return true
-}
-
-// Append a tag directive to the directives stack.
-func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {
- for i := range parser.tag_directives {
- if bytes.Equal(value.handle, parser.tag_directives[i].handle) {
- if allow_duplicates {
- return true
- }
- return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
- }
- }
-
- // [Go] I suspect the copy is unnecessary. This was likely done
- // because there was no way to track ownership of the data.
- value_copy := yaml_tag_directive_t{
- handle: make([]byte, len(value.handle)),
- prefix: make([]byte, len(value.prefix)),
- }
- copy(value_copy.handle, value.handle)
- copy(value_copy.prefix, value.prefix)
- parser.tag_directives = append(parser.tag_directives, value_copy)
- return true
-}
diff --git a/vendor/go.yaml.in/yaml/v2/readerc.go b/vendor/go.yaml.in/yaml/v2/readerc.go
deleted file mode 100644
index 7c1f5fac3d..0000000000
--- a/vendor/go.yaml.in/yaml/v2/readerc.go
+++ /dev/null
@@ -1,412 +0,0 @@
-package yaml
-
-import (
- "io"
-)
-
-// Set the reader error and return 0.
-func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
- parser.error = yaml_READER_ERROR
- parser.problem = problem
- parser.problem_offset = offset
- parser.problem_value = value
- return false
-}
-
-// Byte order marks.
-const (
- bom_UTF8 = "\xef\xbb\xbf"
- bom_UTF16LE = "\xff\xfe"
- bom_UTF16BE = "\xfe\xff"
-)
-
-// Determine the input stream encoding by checking the BOM symbol. If no BOM is
-// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
-func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
- // Ensure that we had enough bytes in the raw buffer.
- for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
- if !yaml_parser_update_raw_buffer(parser) {
- return false
- }
- }
-
- // Determine the encoding.
- buf := parser.raw_buffer
- pos := parser.raw_buffer_pos
- avail := len(buf) - pos
- if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
- parser.encoding = yaml_UTF16LE_ENCODING
- parser.raw_buffer_pos += 2
- parser.offset += 2
- } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
- parser.encoding = yaml_UTF16BE_ENCODING
- parser.raw_buffer_pos += 2
- parser.offset += 2
- } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
- parser.encoding = yaml_UTF8_ENCODING
- parser.raw_buffer_pos += 3
- parser.offset += 3
- } else {
- parser.encoding = yaml_UTF8_ENCODING
- }
- return true
-}
-
-// Update the raw buffer.
-func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
- size_read := 0
-
- // Return if the raw buffer is full.
- if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
- return true
- }
-
- // Return on EOF.
- if parser.eof {
- return true
- }
-
- // Move the remaining bytes in the raw buffer to the beginning.
- if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
- copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
- }
- parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
- parser.raw_buffer_pos = 0
-
- // Call the read handler to fill the buffer.
- size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
- parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
- if err == io.EOF {
- parser.eof = true
- } else if err != nil {
- return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
- }
- return true
-}
-
-// Ensure that the buffer contains at least `length` characters.
-// Return true on success, false on failure.
-//
-// The length is supposed to be significantly less that the buffer size.
-func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
- if parser.read_handler == nil {
- panic("read handler must be set")
- }
-
- // [Go] This function was changed to guarantee the requested length size at EOF.
- // The fact we need to do this is pretty awful, but the description above implies
- // for that to be the case, and there are tests
-
- // If the EOF flag is set and the raw buffer is empty, do nothing.
- if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
- // [Go] ACTUALLY! Read the documentation of this function above.
- // This is just broken. To return true, we need to have the
- // given length in the buffer. Not doing that means every single
- // check that calls this function to make sure the buffer has a
- // given length is Go) panicking; or C) accessing invalid memory.
- //return true
- }
-
- // Return if the buffer contains enough characters.
- if parser.unread >= length {
- return true
- }
-
- // Determine the input encoding if it is not known yet.
- if parser.encoding == yaml_ANY_ENCODING {
- if !yaml_parser_determine_encoding(parser) {
- return false
- }
- }
-
- // Move the unread characters to the beginning of the buffer.
- buffer_len := len(parser.buffer)
- if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
- copy(parser.buffer, parser.buffer[parser.buffer_pos:])
- buffer_len -= parser.buffer_pos
- parser.buffer_pos = 0
- } else if parser.buffer_pos == buffer_len {
- buffer_len = 0
- parser.buffer_pos = 0
- }
-
- // Open the whole buffer for writing, and cut it before returning.
- parser.buffer = parser.buffer[:cap(parser.buffer)]
-
- // Fill the buffer until it has enough characters.
- first := true
- for parser.unread < length {
-
- // Fill the raw buffer if necessary.
- if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
- if !yaml_parser_update_raw_buffer(parser) {
- parser.buffer = parser.buffer[:buffer_len]
- return false
- }
- }
- first = false
-
- // Decode the raw buffer.
- inner:
- for parser.raw_buffer_pos != len(parser.raw_buffer) {
- var value rune
- var width int
-
- raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
-
- // Decode the next character.
- switch parser.encoding {
- case yaml_UTF8_ENCODING:
- // Decode a UTF-8 character. Check RFC 3629
- // (http://www.ietf.org/rfc/rfc3629.txt) for more details.
- //
- // The following table (taken from the RFC) is used for
- // decoding.
- //
- // Char. number range | UTF-8 octet sequence
- // (hexadecimal) | (binary)
- // --------------------+------------------------------------
- // 0000 0000-0000 007F | 0xxxxxxx
- // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
- // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
- // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- //
- // Additionally, the characters in the range 0xD800-0xDFFF
- // are prohibited as they are reserved for use with UTF-16
- // surrogate pairs.
-
- // Determine the length of the UTF-8 sequence.
- octet := parser.raw_buffer[parser.raw_buffer_pos]
- switch {
- case octet&0x80 == 0x00:
- width = 1
- case octet&0xE0 == 0xC0:
- width = 2
- case octet&0xF0 == 0xE0:
- width = 3
- case octet&0xF8 == 0xF0:
- width = 4
- default:
- // The leading octet is invalid.
- return yaml_parser_set_reader_error(parser,
- "invalid leading UTF-8 octet",
- parser.offset, int(octet))
- }
-
- // Check if the raw buffer contains an incomplete character.
- if width > raw_unread {
- if parser.eof {
- return yaml_parser_set_reader_error(parser,
- "incomplete UTF-8 octet sequence",
- parser.offset, -1)
- }
- break inner
- }
-
- // Decode the leading octet.
- switch {
- case octet&0x80 == 0x00:
- value = rune(octet & 0x7F)
- case octet&0xE0 == 0xC0:
- value = rune(octet & 0x1F)
- case octet&0xF0 == 0xE0:
- value = rune(octet & 0x0F)
- case octet&0xF8 == 0xF0:
- value = rune(octet & 0x07)
- default:
- value = 0
- }
-
- // Check and decode the trailing octets.
- for k := 1; k < width; k++ {
- octet = parser.raw_buffer[parser.raw_buffer_pos+k]
-
- // Check if the octet is valid.
- if (octet & 0xC0) != 0x80 {
- return yaml_parser_set_reader_error(parser,
- "invalid trailing UTF-8 octet",
- parser.offset+k, int(octet))
- }
-
- // Decode the octet.
- value = (value << 6) + rune(octet&0x3F)
- }
-
- // Check the length of the sequence against the value.
- switch {
- case width == 1:
- case width == 2 && value >= 0x80:
- case width == 3 && value >= 0x800:
- case width == 4 && value >= 0x10000:
- default:
- return yaml_parser_set_reader_error(parser,
- "invalid length of a UTF-8 sequence",
- parser.offset, -1)
- }
-
- // Check the range of the value.
- if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
- return yaml_parser_set_reader_error(parser,
- "invalid Unicode character",
- parser.offset, int(value))
- }
-
- case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
- var low, high int
- if parser.encoding == yaml_UTF16LE_ENCODING {
- low, high = 0, 1
- } else {
- low, high = 1, 0
- }
-
- // The UTF-16 encoding is not as simple as one might
- // naively think. Check RFC 2781
- // (http://www.ietf.org/rfc/rfc2781.txt).
- //
- // Normally, two subsequent bytes describe a Unicode
- // character. However a special technique (called a
- // surrogate pair) is used for specifying character
- // values larger than 0xFFFF.
- //
- // A surrogate pair consists of two pseudo-characters:
- // high surrogate area (0xD800-0xDBFF)
- // low surrogate area (0xDC00-0xDFFF)
- //
- // The following formulas are used for decoding
- // and encoding characters using surrogate pairs:
- //
- // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
- // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
- // W1 = 110110yyyyyyyyyy
- // W2 = 110111xxxxxxxxxx
- //
- // where U is the character value, W1 is the high surrogate
- // area, W2 is the low surrogate area.
-
- // Check for incomplete UTF-16 character.
- if raw_unread < 2 {
- if parser.eof {
- return yaml_parser_set_reader_error(parser,
- "incomplete UTF-16 character",
- parser.offset, -1)
- }
- break inner
- }
-
- // Get the character.
- value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
- (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
-
- // Check for unexpected low surrogate area.
- if value&0xFC00 == 0xDC00 {
- return yaml_parser_set_reader_error(parser,
- "unexpected low surrogate area",
- parser.offset, int(value))
- }
-
- // Check for a high surrogate area.
- if value&0xFC00 == 0xD800 {
- width = 4
-
- // Check for incomplete surrogate pair.
- if raw_unread < 4 {
- if parser.eof {
- return yaml_parser_set_reader_error(parser,
- "incomplete UTF-16 surrogate pair",
- parser.offset, -1)
- }
- break inner
- }
-
- // Get the next character.
- value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
- (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
-
- // Check for a low surrogate area.
- if value2&0xFC00 != 0xDC00 {
- return yaml_parser_set_reader_error(parser,
- "expected low surrogate area",
- parser.offset+2, int(value2))
- }
-
- // Generate the value of the surrogate pair.
- value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
- } else {
- width = 2
- }
-
- default:
- panic("impossible")
- }
-
- // Check if the character is in the allowed range:
- // #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
- // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
- // | [#x10000-#x10FFFF] (32 bit)
- switch {
- case value == 0x09:
- case value == 0x0A:
- case value == 0x0D:
- case value >= 0x20 && value <= 0x7E:
- case value == 0x85:
- case value >= 0xA0 && value <= 0xD7FF:
- case value >= 0xE000 && value <= 0xFFFD:
- case value >= 0x10000 && value <= 0x10FFFF:
- default:
- return yaml_parser_set_reader_error(parser,
- "control characters are not allowed",
- parser.offset, int(value))
- }
-
- // Move the raw pointers.
- parser.raw_buffer_pos += width
- parser.offset += width
-
- // Finally put the character into the buffer.
- if value <= 0x7F {
- // 0000 0000-0000 007F . 0xxxxxxx
- parser.buffer[buffer_len+0] = byte(value)
- buffer_len += 1
- } else if value <= 0x7FF {
- // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
- parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
- parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
- buffer_len += 2
- } else if value <= 0xFFFF {
- // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
- parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
- parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
- parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
- buffer_len += 3
- } else {
- // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
- parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
- parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
- parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
- buffer_len += 4
- }
-
- parser.unread++
- }
-
- // On EOF, put NUL into the buffer and return.
- if parser.eof {
- parser.buffer[buffer_len] = 0
- buffer_len++
- parser.unread++
- break
- }
- }
- // [Go] Read the documentation of this function above. To return true,
- // we need to have the given length in the buffer. Not doing that means
- // every single check that calls this function to make sure the buffer
- // has a given length is Go) panicking; or C) accessing invalid memory.
- // This happens here due to the EOF above breaking early.
- for buffer_len < length {
- parser.buffer[buffer_len] = 0
- buffer_len++
- }
- parser.buffer = parser.buffer[:buffer_len]
- return true
-}
diff --git a/vendor/go.yaml.in/yaml/v2/resolve.go b/vendor/go.yaml.in/yaml/v2/resolve.go
deleted file mode 100644
index 4120e0c916..0000000000
--- a/vendor/go.yaml.in/yaml/v2/resolve.go
+++ /dev/null
@@ -1,258 +0,0 @@
-package yaml
-
-import (
- "encoding/base64"
- "math"
- "regexp"
- "strconv"
- "strings"
- "time"
-)
-
-type resolveMapItem struct {
- value interface{}
- tag string
-}
-
-var resolveTable = make([]byte, 256)
-var resolveMap = make(map[string]resolveMapItem)
-
-func init() {
- t := resolveTable
- t[int('+')] = 'S' // Sign
- t[int('-')] = 'S'
- for _, c := range "0123456789" {
- t[int(c)] = 'D' // Digit
- }
- for _, c := range "yYnNtTfFoO~" {
- t[int(c)] = 'M' // In map
- }
- t[int('.')] = '.' // Float (potentially in map)
-
- var resolveMapList = []struct {
- v interface{}
- tag string
- l []string
- }{
- {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}},
- {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}},
- {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}},
- {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}},
- {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}},
- {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}},
- {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}},
- {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}},
- {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}},
- {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}},
- {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}},
- {"<<", yaml_MERGE_TAG, []string{"<<"}},
- }
-
- m := resolveMap
- for _, item := range resolveMapList {
- for _, s := range item.l {
- m[s] = resolveMapItem{item.v, item.tag}
- }
- }
-}
-
-const longTagPrefix = "tag:yaml.org,2002:"
-
-func shortTag(tag string) string {
- // TODO This can easily be made faster and produce less garbage.
- if strings.HasPrefix(tag, longTagPrefix) {
- return "!!" + tag[len(longTagPrefix):]
- }
- return tag
-}
-
-func longTag(tag string) string {
- if strings.HasPrefix(tag, "!!") {
- return longTagPrefix + tag[2:]
- }
- return tag
-}
-
-func resolvableTag(tag string) bool {
- switch tag {
- case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG:
- return true
- }
- return false
-}
-
-var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
-
-func resolve(tag string, in string) (rtag string, out interface{}) {
- if !resolvableTag(tag) {
- return tag, in
- }
-
- defer func() {
- switch tag {
- case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG:
- return
- case yaml_FLOAT_TAG:
- if rtag == yaml_INT_TAG {
- switch v := out.(type) {
- case int64:
- rtag = yaml_FLOAT_TAG
- out = float64(v)
- return
- case int:
- rtag = yaml_FLOAT_TAG
- out = float64(v)
- return
- }
- }
- }
- failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
- }()
-
- // Any data is accepted as a !!str or !!binary.
- // Otherwise, the prefix is enough of a hint about what it might be.
- hint := byte('N')
- if in != "" {
- hint = resolveTable[in[0]]
- }
- if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG {
- // Handle things we can lookup in a map.
- if item, ok := resolveMap[in]; ok {
- return item.tag, item.value
- }
-
- // Base 60 floats are a bad idea, were dropped in YAML 1.2, and
- // are purposefully unsupported here. They're still quoted on
- // the way out for compatibility with other parser, though.
-
- switch hint {
- case 'M':
- // We've already checked the map above.
-
- case '.':
- // Not in the map, so maybe a normal float.
- floatv, err := strconv.ParseFloat(in, 64)
- if err == nil {
- return yaml_FLOAT_TAG, floatv
- }
-
- case 'D', 'S':
- // Int, float, or timestamp.
- // Only try values as a timestamp if the value is unquoted or there's an explicit
- // !!timestamp tag.
- if tag == "" || tag == yaml_TIMESTAMP_TAG {
- t, ok := parseTimestamp(in)
- if ok {
- return yaml_TIMESTAMP_TAG, t
- }
- }
-
- plain := strings.Replace(in, "_", "", -1)
- intv, err := strconv.ParseInt(plain, 0, 64)
- if err == nil {
- if intv == int64(int(intv)) {
- return yaml_INT_TAG, int(intv)
- } else {
- return yaml_INT_TAG, intv
- }
- }
- uintv, err := strconv.ParseUint(plain, 0, 64)
- if err == nil {
- return yaml_INT_TAG, uintv
- }
- if yamlStyleFloat.MatchString(plain) {
- floatv, err := strconv.ParseFloat(plain, 64)
- if err == nil {
- return yaml_FLOAT_TAG, floatv
- }
- }
- if strings.HasPrefix(plain, "0b") {
- intv, err := strconv.ParseInt(plain[2:], 2, 64)
- if err == nil {
- if intv == int64(int(intv)) {
- return yaml_INT_TAG, int(intv)
- } else {
- return yaml_INT_TAG, intv
- }
- }
- uintv, err := strconv.ParseUint(plain[2:], 2, 64)
- if err == nil {
- return yaml_INT_TAG, uintv
- }
- } else if strings.HasPrefix(plain, "-0b") {
- intv, err := strconv.ParseInt("-" + plain[3:], 2, 64)
- if err == nil {
- if true || intv == int64(int(intv)) {
- return yaml_INT_TAG, int(intv)
- } else {
- return yaml_INT_TAG, intv
- }
- }
- }
- default:
- panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")")
- }
- }
- return yaml_STR_TAG, in
-}
-
-// encodeBase64 encodes s as base64 that is broken up into multiple lines
-// as appropriate for the resulting length.
-func encodeBase64(s string) string {
- const lineLen = 70
- encLen := base64.StdEncoding.EncodedLen(len(s))
- lines := encLen/lineLen + 1
- buf := make([]byte, encLen*2+lines)
- in := buf[0:encLen]
- out := buf[encLen:]
- base64.StdEncoding.Encode(in, []byte(s))
- k := 0
- for i := 0; i < len(in); i += lineLen {
- j := i + lineLen
- if j > len(in) {
- j = len(in)
- }
- k += copy(out[k:], in[i:j])
- if lines > 1 {
- out[k] = '\n'
- k++
- }
- }
- return string(out[:k])
-}
-
-// This is a subset of the formats allowed by the regular expression
-// defined at http://yaml.org/type/timestamp.html.
-var allowedTimestampFormats = []string{
- "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
- "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
- "2006-1-2 15:4:5.999999999", // space separated with no time zone
- "2006-1-2", // date only
- // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
- // from the set of examples.
-}
-
-// parseTimestamp parses s as a timestamp string and
-// returns the timestamp and reports whether it succeeded.
-// Timestamp formats are defined at http://yaml.org/type/timestamp.html
-func parseTimestamp(s string) (time.Time, bool) {
- // TODO write code to check all the formats supported by
- // http://yaml.org/type/timestamp.html instead of using time.Parse.
-
- // Quick check: all date formats start with YYYY-.
- i := 0
- for ; i < len(s); i++ {
- if c := s[i]; c < '0' || c > '9' {
- break
- }
- }
- if i != 4 || i == len(s) || s[i] != '-' {
- return time.Time{}, false
- }
- for _, format := range allowedTimestampFormats {
- if t, err := time.Parse(format, s); err == nil {
- return t, true
- }
- }
- return time.Time{}, false
-}
diff --git a/vendor/go.yaml.in/yaml/v2/scannerc.go b/vendor/go.yaml.in/yaml/v2/scannerc.go
deleted file mode 100644
index 0b9bb6030a..0000000000
--- a/vendor/go.yaml.in/yaml/v2/scannerc.go
+++ /dev/null
@@ -1,2711 +0,0 @@
-package yaml
-
-import (
- "bytes"
- "fmt"
-)
-
-// Introduction
-// ************
-//
-// The following notes assume that you are familiar with the YAML specification
-// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in
-// some cases we are less restrictive that it requires.
-//
-// The process of transforming a YAML stream into a sequence of events is
-// divided on two steps: Scanning and Parsing.
-//
-// The Scanner transforms the input stream into a sequence of tokens, while the
-// parser transform the sequence of tokens produced by the Scanner into a
-// sequence of parsing events.
-//
-// The Scanner is rather clever and complicated. The Parser, on the contrary,
-// is a straightforward implementation of a recursive-descendant parser (or,
-// LL(1) parser, as it is usually called).
-//
-// Actually there are two issues of Scanning that might be called "clever", the
-// rest is quite straightforward. The issues are "block collection start" and
-// "simple keys". Both issues are explained below in details.
-//
-// Here the Scanning step is explained and implemented. We start with the list
-// of all the tokens produced by the Scanner together with short descriptions.
-//
-// Now, tokens:
-//
-// STREAM-START(encoding) # The stream start.
-// STREAM-END # The stream end.
-// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.
-// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.
-// DOCUMENT-START # '---'
-// DOCUMENT-END # '...'
-// BLOCK-SEQUENCE-START # Indentation increase denoting a block
-// BLOCK-MAPPING-START # sequence or a block mapping.
-// BLOCK-END # Indentation decrease.
-// FLOW-SEQUENCE-START # '['
-// FLOW-SEQUENCE-END # ']'
-// BLOCK-SEQUENCE-START # '{'
-// BLOCK-SEQUENCE-END # '}'
-// BLOCK-ENTRY # '-'
-// FLOW-ENTRY # ','
-// KEY # '?' or nothing (simple keys).
-// VALUE # ':'
-// ALIAS(anchor) # '*anchor'
-// ANCHOR(anchor) # '&anchor'
-// TAG(handle,suffix) # '!handle!suffix'
-// SCALAR(value,style) # A scalar.
-//
-// The following two tokens are "virtual" tokens denoting the beginning and the
-// end of the stream:
-//
-// STREAM-START(encoding)
-// STREAM-END
-//
-// We pass the information about the input stream encoding with the
-// STREAM-START token.
-//
-// The next two tokens are responsible for tags:
-//
-// VERSION-DIRECTIVE(major,minor)
-// TAG-DIRECTIVE(handle,prefix)
-//
-// Example:
-//
-// %YAML 1.1
-// %TAG ! !foo
-// %TAG !yaml! tag:yaml.org,2002:
-// ---
-//
-// The correspoding sequence of tokens:
-//
-// STREAM-START(utf-8)
-// VERSION-DIRECTIVE(1,1)
-// TAG-DIRECTIVE("!","!foo")
-// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
-// DOCUMENT-START
-// STREAM-END
-//
-// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
-// line.
-//
-// The document start and end indicators are represented by:
-//
-// DOCUMENT-START
-// DOCUMENT-END
-//
-// Note that if a YAML stream contains an implicit document (without '---'
-// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
-// produced.
-//
-// In the following examples, we present whole documents together with the
-// produced tokens.
-//
-// 1. An implicit document:
-//
-// 'a scalar'
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// SCALAR("a scalar",single-quoted)
-// STREAM-END
-//
-// 2. An explicit document:
-//
-// ---
-// 'a scalar'
-// ...
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// DOCUMENT-START
-// SCALAR("a scalar",single-quoted)
-// DOCUMENT-END
-// STREAM-END
-//
-// 3. Several documents in a stream:
-//
-// 'a scalar'
-// ---
-// 'another scalar'
-// ---
-// 'yet another scalar'
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// SCALAR("a scalar",single-quoted)
-// DOCUMENT-START
-// SCALAR("another scalar",single-quoted)
-// DOCUMENT-START
-// SCALAR("yet another scalar",single-quoted)
-// STREAM-END
-//
-// We have already introduced the SCALAR token above. The following tokens are
-// used to describe aliases, anchors, tag, and scalars:
-//
-// ALIAS(anchor)
-// ANCHOR(anchor)
-// TAG(handle,suffix)
-// SCALAR(value,style)
-//
-// The following series of examples illustrate the usage of these tokens:
-//
-// 1. A recursive sequence:
-//
-// &A [ *A ]
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// ANCHOR("A")
-// FLOW-SEQUENCE-START
-// ALIAS("A")
-// FLOW-SEQUENCE-END
-// STREAM-END
-//
-// 2. A tagged scalar:
-//
-// !!float "3.14" # A good approximation.
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// TAG("!!","float")
-// SCALAR("3.14",double-quoted)
-// STREAM-END
-//
-// 3. Various scalar styles:
-//
-// --- # Implicit empty plain scalars do not produce tokens.
-// --- a plain scalar
-// --- 'a single-quoted scalar'
-// --- "a double-quoted scalar"
-// --- |-
-// a literal scalar
-// --- >-
-// a folded
-// scalar
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// DOCUMENT-START
-// DOCUMENT-START
-// SCALAR("a plain scalar",plain)
-// DOCUMENT-START
-// SCALAR("a single-quoted scalar",single-quoted)
-// DOCUMENT-START
-// SCALAR("a double-quoted scalar",double-quoted)
-// DOCUMENT-START
-// SCALAR("a literal scalar",literal)
-// DOCUMENT-START
-// SCALAR("a folded scalar",folded)
-// STREAM-END
-//
-// Now it's time to review collection-related tokens. We will start with
-// flow collections:
-//
-// FLOW-SEQUENCE-START
-// FLOW-SEQUENCE-END
-// FLOW-MAPPING-START
-// FLOW-MAPPING-END
-// FLOW-ENTRY
-// KEY
-// VALUE
-//
-// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
-// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
-// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the
-// indicators '?' and ':', which are used for denoting mapping keys and values,
-// are represented by the KEY and VALUE tokens.
-//
-// The following examples show flow collections:
-//
-// 1. A flow sequence:
-//
-// [item 1, item 2, item 3]
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// FLOW-SEQUENCE-START
-// SCALAR("item 1",plain)
-// FLOW-ENTRY
-// SCALAR("item 2",plain)
-// FLOW-ENTRY
-// SCALAR("item 3",plain)
-// FLOW-SEQUENCE-END
-// STREAM-END
-//
-// 2. A flow mapping:
-//
-// {
-// a simple key: a value, # Note that the KEY token is produced.
-// ? a complex key: another value,
-// }
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// FLOW-MAPPING-START
-// KEY
-// SCALAR("a simple key",plain)
-// VALUE
-// SCALAR("a value",plain)
-// FLOW-ENTRY
-// KEY
-// SCALAR("a complex key",plain)
-// VALUE
-// SCALAR("another value",plain)
-// FLOW-ENTRY
-// FLOW-MAPPING-END
-// STREAM-END
-//
-// A simple key is a key which is not denoted by the '?' indicator. Note that
-// the Scanner still produce the KEY token whenever it encounters a simple key.
-//
-// For scanning block collections, the following tokens are used (note that we
-// repeat KEY and VALUE here):
-//
-// BLOCK-SEQUENCE-START
-// BLOCK-MAPPING-START
-// BLOCK-END
-// BLOCK-ENTRY
-// KEY
-// VALUE
-//
-// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
-// increase that precedes a block collection (cf. the INDENT token in Python).
-// The token BLOCK-END denote indentation decrease that ends a block collection
-// (cf. the DEDENT token in Python). However YAML has some syntax pecularities
-// that makes detections of these tokens more complex.
-//
-// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
-// '-', '?', and ':' correspondingly.
-//
-// The following examples show how the tokens BLOCK-SEQUENCE-START,
-// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
-//
-// 1. Block sequences:
-//
-// - item 1
-// - item 2
-// -
-// - item 3.1
-// - item 3.2
-// -
-// key 1: value 1
-// key 2: value 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-ENTRY
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 3.1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 3.2",plain)
-// BLOCK-END
-// BLOCK-ENTRY
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// 2. Block mappings:
-//
-// a simple key: a value # The KEY token is produced here.
-// ? a complex key
-// : another value
-// a mapping:
-// key 1: value 1
-// key 2: value 2
-// a sequence:
-// - item 1
-// - item 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("a simple key",plain)
-// VALUE
-// SCALAR("a value",plain)
-// KEY
-// SCALAR("a complex key",plain)
-// VALUE
-// SCALAR("another value",plain)
-// KEY
-// SCALAR("a mapping",plain)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// KEY
-// SCALAR("a sequence",plain)
-// VALUE
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// YAML does not always require to start a new block collection from a new
-// line. If the current line contains only '-', '?', and ':' indicators, a new
-// block collection may start at the current line. The following examples
-// illustrate this case:
-//
-// 1. Collections in a sequence:
-//
-// - - item 1
-// - item 2
-// - key 1: value 1
-// key 2: value 2
-// - ? complex key
-// : complex value
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-// BLOCK-ENTRY
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// BLOCK-ENTRY
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("complex key")
-// VALUE
-// SCALAR("complex value")
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// 2. Collections in a mapping:
-//
-// ? a sequence
-// : - item 1
-// - item 2
-// ? a mapping
-// : key 1: value 1
-// key 2: value 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("a sequence",plain)
-// VALUE
-// BLOCK-SEQUENCE-START
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-// KEY
-// SCALAR("a mapping",plain)
-// VALUE
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key 1",plain)
-// VALUE
-// SCALAR("value 1",plain)
-// KEY
-// SCALAR("key 2",plain)
-// VALUE
-// SCALAR("value 2",plain)
-// BLOCK-END
-// BLOCK-END
-// STREAM-END
-//
-// YAML also permits non-indented sequences if they are included into a block
-// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced:
-//
-// key:
-// - item 1 # BLOCK-SEQUENCE-START is NOT produced here.
-// - item 2
-//
-// Tokens:
-//
-// STREAM-START(utf-8)
-// BLOCK-MAPPING-START
-// KEY
-// SCALAR("key",plain)
-// VALUE
-// BLOCK-ENTRY
-// SCALAR("item 1",plain)
-// BLOCK-ENTRY
-// SCALAR("item 2",plain)
-// BLOCK-END
-//
-
-// Ensure that the buffer contains the required number of characters.
-// Return true on success, false on failure (reader error or memory error).
-func cache(parser *yaml_parser_t, length int) bool {
- // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)
- return parser.unread >= length || yaml_parser_update_buffer(parser, length)
-}
-
-// Advance the buffer pointer.
-func skip(parser *yaml_parser_t) {
- parser.mark.index++
- parser.mark.column++
- parser.unread--
- parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
-}
-
-func skip_line(parser *yaml_parser_t) {
- if is_crlf(parser.buffer, parser.buffer_pos) {
- parser.mark.index += 2
- parser.mark.column = 0
- parser.mark.line++
- parser.unread -= 2
- parser.buffer_pos += 2
- } else if is_break(parser.buffer, parser.buffer_pos) {
- parser.mark.index++
- parser.mark.column = 0
- parser.mark.line++
- parser.unread--
- parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
- }
-}
-
-// Copy a character to a string buffer and advance pointers.
-func read(parser *yaml_parser_t, s []byte) []byte {
- w := width(parser.buffer[parser.buffer_pos])
- if w == 0 {
- panic("invalid character sequence")
- }
- if len(s) == 0 {
- s = make([]byte, 0, 32)
- }
- if w == 1 && len(s)+w <= cap(s) {
- s = s[:len(s)+1]
- s[len(s)-1] = parser.buffer[parser.buffer_pos]
- parser.buffer_pos++
- } else {
- s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)
- parser.buffer_pos += w
- }
- parser.mark.index++
- parser.mark.column++
- parser.unread--
- return s
-}
-
-// Copy a line break character to a string buffer and advance pointers.
-func read_line(parser *yaml_parser_t, s []byte) []byte {
- buf := parser.buffer
- pos := parser.buffer_pos
- switch {
- case buf[pos] == '\r' && buf[pos+1] == '\n':
- // CR LF . LF
- s = append(s, '\n')
- parser.buffer_pos += 2
- parser.mark.index++
- parser.unread--
- case buf[pos] == '\r' || buf[pos] == '\n':
- // CR|LF . LF
- s = append(s, '\n')
- parser.buffer_pos += 1
- case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
- // NEL . LF
- s = append(s, '\n')
- parser.buffer_pos += 2
- case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
- // LS|PS . LS|PS
- s = append(s, buf[parser.buffer_pos:pos+3]...)
- parser.buffer_pos += 3
- default:
- return s
- }
- parser.mark.index++
- parser.mark.column = 0
- parser.mark.line++
- parser.unread--
- return s
-}
-
-// Get the next token.
-func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
- // Erase the token object.
- *token = yaml_token_t{} // [Go] Is this necessary?
-
- // No tokens after STREAM-END or error.
- if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
- return true
- }
-
- // Ensure that the tokens queue contains enough tokens.
- if !parser.token_available {
- if !yaml_parser_fetch_more_tokens(parser) {
- return false
- }
- }
-
- // Fetch the next token from the queue.
- *token = parser.tokens[parser.tokens_head]
- parser.tokens_head++
- parser.tokens_parsed++
- parser.token_available = false
-
- if token.typ == yaml_STREAM_END_TOKEN {
- parser.stream_end_produced = true
- }
- return true
-}
-
-// Set the scanner error and return false.
-func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
- parser.error = yaml_SCANNER_ERROR
- parser.context = context
- parser.context_mark = context_mark
- parser.problem = problem
- parser.problem_mark = parser.mark
- return false
-}
-
-func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
- context := "while parsing a tag"
- if directive {
- context = "while parsing a %TAG directive"
- }
- return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
-}
-
-func trace(args ...interface{}) func() {
- pargs := append([]interface{}{"+++"}, args...)
- fmt.Println(pargs...)
- pargs = append([]interface{}{"---"}, args...)
- return func() { fmt.Println(pargs...) }
-}
-
-// Ensure that the tokens queue contains at least one token which can be
-// returned to the Parser.
-func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
- // While we need more tokens to fetch, do it.
- for {
- if parser.tokens_head != len(parser.tokens) {
- // If queue is non-empty, check if any potential simple key may
- // occupy the head position.
- head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
- if !ok {
- break
- } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
- return false
- } else if !valid {
- break
- }
- }
- // Fetch the next token.
- if !yaml_parser_fetch_next_token(parser) {
- return false
- }
- }
-
- parser.token_available = true
- return true
-}
-
-// The dispatcher for token fetchers.
-func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
- // Ensure that the buffer is initialized.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // Check if we just started scanning. Fetch STREAM-START then.
- if !parser.stream_start_produced {
- return yaml_parser_fetch_stream_start(parser)
- }
-
- // Eat whitespaces and comments until we reach the next token.
- if !yaml_parser_scan_to_next_token(parser) {
- return false
- }
-
- // Check the indentation level against the current column.
- if !yaml_parser_unroll_indent(parser, parser.mark.column) {
- return false
- }
-
- // Ensure that the buffer contains at least 4 characters. 4 is the length
- // of the longest indicators ('--- ' and '... ').
- if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
- return false
- }
-
- // Is it the end of the stream?
- if is_z(parser.buffer, parser.buffer_pos) {
- return yaml_parser_fetch_stream_end(parser)
- }
-
- // Is it a directive?
- if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
- return yaml_parser_fetch_directive(parser)
- }
-
- buf := parser.buffer
- pos := parser.buffer_pos
-
- // Is it the document start indicator?
- if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
- return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
- }
-
- // Is it the document end indicator?
- if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
- return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
- }
-
- // Is it the flow sequence start indicator?
- if buf[pos] == '[' {
- return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
- }
-
- // Is it the flow mapping start indicator?
- if parser.buffer[parser.buffer_pos] == '{' {
- return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
- }
-
- // Is it the flow sequence end indicator?
- if parser.buffer[parser.buffer_pos] == ']' {
- return yaml_parser_fetch_flow_collection_end(parser,
- yaml_FLOW_SEQUENCE_END_TOKEN)
- }
-
- // Is it the flow mapping end indicator?
- if parser.buffer[parser.buffer_pos] == '}' {
- return yaml_parser_fetch_flow_collection_end(parser,
- yaml_FLOW_MAPPING_END_TOKEN)
- }
-
- // Is it the flow entry indicator?
- if parser.buffer[parser.buffer_pos] == ',' {
- return yaml_parser_fetch_flow_entry(parser)
- }
-
- // Is it the block entry indicator?
- if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
- return yaml_parser_fetch_block_entry(parser)
- }
-
- // Is it the key indicator?
- if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
- return yaml_parser_fetch_key(parser)
- }
-
- // Is it the value indicator?
- if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
- return yaml_parser_fetch_value(parser)
- }
-
- // Is it an alias?
- if parser.buffer[parser.buffer_pos] == '*' {
- return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
- }
-
- // Is it an anchor?
- if parser.buffer[parser.buffer_pos] == '&' {
- return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
- }
-
- // Is it a tag?
- if parser.buffer[parser.buffer_pos] == '!' {
- return yaml_parser_fetch_tag(parser)
- }
-
- // Is it a literal scalar?
- if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
- return yaml_parser_fetch_block_scalar(parser, true)
- }
-
- // Is it a folded scalar?
- if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
- return yaml_parser_fetch_block_scalar(parser, false)
- }
-
- // Is it a single-quoted scalar?
- if parser.buffer[parser.buffer_pos] == '\'' {
- return yaml_parser_fetch_flow_scalar(parser, true)
- }
-
- // Is it a double-quoted scalar?
- if parser.buffer[parser.buffer_pos] == '"' {
- return yaml_parser_fetch_flow_scalar(parser, false)
- }
-
- // Is it a plain scalar?
- //
- // A plain scalar may start with any non-blank characters except
- //
- // '-', '?', ':', ',', '[', ']', '{', '}',
- // '#', '&', '*', '!', '|', '>', '\'', '\"',
- // '%', '@', '`'.
- //
- // In the block context (and, for the '-' indicator, in the flow context
- // too), it may also start with the characters
- //
- // '-', '?', ':'
- //
- // if it is followed by a non-space character.
- //
- // The last rule is more restrictive than the specification requires.
- // [Go] Make this logic more reasonable.
- //switch parser.buffer[parser.buffer_pos] {
- //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':
- //}
- if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
- parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
- parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
- parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
- parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
- parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
- parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
- parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
- parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
- parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
- (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
- (parser.flow_level == 0 &&
- (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
- !is_blankz(parser.buffer, parser.buffer_pos+1)) {
- return yaml_parser_fetch_plain_scalar(parser)
- }
-
- // If we don't determine the token type so far, it is an error.
- return yaml_parser_set_scanner_error(parser,
- "while scanning for the next token", parser.mark,
- "found character that cannot start any token")
-}
-
-func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
- if !simple_key.possible {
- return false, true
- }
-
- // The 1.2 specification says:
- //
- // "If the ? indicator is omitted, parsing needs to see past the
- // implicit key to recognize it as such. To limit the amount of
- // lookahead required, the “:” indicator must appear at most 1024
- // Unicode characters beyond the start of the key. In addition, the key
- // is restricted to a single line."
- //
- if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
- // Check if the potential simple key to be removed is required.
- if simple_key.required {
- return false, yaml_parser_set_scanner_error(parser,
- "while scanning a simple key", simple_key.mark,
- "could not find expected ':'")
- }
- simple_key.possible = false
- return false, true
- }
- return true, true
-}
-
-// Check if a simple key may start at the current position and add it if
-// needed.
-func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
- // A simple key is required at the current position if the scanner is in
- // the block context and the current column coincides with the indentation
- // level.
-
- required := parser.flow_level == 0 && parser.indent == parser.mark.column
-
- //
- // If the current position may start a simple key, save it.
- //
- if parser.simple_key_allowed {
- simple_key := yaml_simple_key_t{
- possible: true,
- required: required,
- token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
- mark: parser.mark,
- }
-
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
- parser.simple_keys[len(parser.simple_keys)-1] = simple_key
- parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
- }
- return true
-}
-
-// Remove a potential simple key at the current flow level.
-func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
- i := len(parser.simple_keys) - 1
- if parser.simple_keys[i].possible {
- // If the key is required, it is an error.
- if parser.simple_keys[i].required {
- return yaml_parser_set_scanner_error(parser,
- "while scanning a simple key", parser.simple_keys[i].mark,
- "could not find expected ':'")
- }
- // Remove the key from the stack.
- parser.simple_keys[i].possible = false
- delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
- }
- return true
-}
-
-// max_flow_level limits the flow_level
-const max_flow_level = 10000
-
-// Increase the flow level and resize the simple key list if needed.
-func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
- // Reset the simple key on the next level.
- parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
- possible: false,
- required: false,
- token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
- mark: parser.mark,
- })
-
- // Increase the flow level.
- parser.flow_level++
- if parser.flow_level > max_flow_level {
- return yaml_parser_set_scanner_error(parser,
- "while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark,
- fmt.Sprintf("exceeded max depth of %d", max_flow_level))
- }
- return true
-}
-
-// Decrease the flow level.
-func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
- if parser.flow_level > 0 {
- parser.flow_level--
- last := len(parser.simple_keys) - 1
- delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
- parser.simple_keys = parser.simple_keys[:last]
- }
- return true
-}
-
-// max_indents limits the indents stack size
-const max_indents = 10000
-
-// Push the current indentation level to the stack and set the new level
-// the current column is greater than the indentation level. In this case,
-// append or insert the specified token into the token queue.
-func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
- // In the flow context, do nothing.
- if parser.flow_level > 0 {
- return true
- }
-
- if parser.indent < column {
- // Push the current indentation level to the stack and set the new
- // indentation level.
- parser.indents = append(parser.indents, parser.indent)
- parser.indent = column
- if len(parser.indents) > max_indents {
- return yaml_parser_set_scanner_error(parser,
- "while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark,
- fmt.Sprintf("exceeded max depth of %d", max_indents))
- }
-
- // Create a token and insert it into the queue.
- token := yaml_token_t{
- typ: typ,
- start_mark: mark,
- end_mark: mark,
- }
- if number > -1 {
- number -= parser.tokens_parsed
- }
- yaml_insert_token(parser, number, &token)
- }
- return true
-}
-
-// Pop indentation levels from the indents stack until the current level
-// becomes less or equal to the column. For each indentation level, append
-// the BLOCK-END token.
-func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool {
- // In the flow context, do nothing.
- if parser.flow_level > 0 {
- return true
- }
-
- // Loop through the indentation levels in the stack.
- for parser.indent > column {
- // Create a token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_BLOCK_END_TOKEN,
- start_mark: parser.mark,
- end_mark: parser.mark,
- }
- yaml_insert_token(parser, -1, &token)
-
- // Pop the indentation level.
- parser.indent = parser.indents[len(parser.indents)-1]
- parser.indents = parser.indents[:len(parser.indents)-1]
- }
- return true
-}
-
-// Initialize the scanner and produce the STREAM-START token.
-func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
-
- // Set the initial indentation.
- parser.indent = -1
-
- // Initialize the simple key stack.
- parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
-
- parser.simple_keys_by_tok = make(map[int]int)
-
- // A simple key is allowed at the beginning of the stream.
- parser.simple_key_allowed = true
-
- // We have started.
- parser.stream_start_produced = true
-
- // Create the STREAM-START token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_STREAM_START_TOKEN,
- start_mark: parser.mark,
- end_mark: parser.mark,
- encoding: parser.encoding,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the STREAM-END token and shut down the scanner.
-func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
-
- // Force new line.
- if parser.mark.column != 0 {
- parser.mark.column = 0
- parser.mark.line++
- }
-
- // Reset the indentation level.
- if !yaml_parser_unroll_indent(parser, -1) {
- return false
- }
-
- // Reset simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- parser.simple_key_allowed = false
-
- // Create the STREAM-END token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_STREAM_END_TOKEN,
- start_mark: parser.mark,
- end_mark: parser.mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
-func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
- // Reset the indentation level.
- if !yaml_parser_unroll_indent(parser, -1) {
- return false
- }
-
- // Reset simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- parser.simple_key_allowed = false
-
- // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
- token := yaml_token_t{}
- if !yaml_parser_scan_directive(parser, &token) {
- return false
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the DOCUMENT-START or DOCUMENT-END token.
-func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
- // Reset the indentation level.
- if !yaml_parser_unroll_indent(parser, -1) {
- return false
- }
-
- // Reset simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- parser.simple_key_allowed = false
-
- // Consume the token.
- start_mark := parser.mark
-
- skip(parser)
- skip(parser)
- skip(parser)
-
- end_mark := parser.mark
-
- // Create the DOCUMENT-START or DOCUMENT-END token.
- token := yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
-func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
- // The indicators '[' and '{' may start a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // Increase the flow level.
- if !yaml_parser_increase_flow_level(parser) {
- return false
- }
-
- // A simple key may follow the indicators '[' and '{'.
- parser.simple_key_allowed = true
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
- token := yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
-func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
- // Reset any potential simple key on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Decrease the flow level.
- if !yaml_parser_decrease_flow_level(parser) {
- return false
- }
-
- // No simple keys after the indicators ']' and '}'.
- parser.simple_key_allowed = false
-
- // Consume the token.
-
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
- token := yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- // Append the token to the queue.
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the FLOW-ENTRY token.
-func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
- // Reset any potential simple keys on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Simple keys are allowed after ','.
- parser.simple_key_allowed = true
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the FLOW-ENTRY token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_FLOW_ENTRY_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the BLOCK-ENTRY token.
-func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
- // Check if the scanner is in the block context.
- if parser.flow_level == 0 {
- // Check if we are allowed to start a new entry.
- if !parser.simple_key_allowed {
- return yaml_parser_set_scanner_error(parser, "", parser.mark,
- "block sequence entries are not allowed in this context")
- }
- // Add the BLOCK-SEQUENCE-START token if needed.
- if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
- return false
- }
- } else {
- // It is an error for the '-' indicator to occur in the flow context,
- // but we let the Parser detect and report about it because the Parser
- // is able to point to the context.
- }
-
- // Reset any potential simple keys on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Simple keys are allowed after '-'.
- parser.simple_key_allowed = true
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the BLOCK-ENTRY token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_BLOCK_ENTRY_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the KEY token.
-func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
-
- // In the block context, additional checks are required.
- if parser.flow_level == 0 {
- // Check if we are allowed to start a new key (not nessesary simple).
- if !parser.simple_key_allowed {
- return yaml_parser_set_scanner_error(parser, "", parser.mark,
- "mapping keys are not allowed in this context")
- }
- // Add the BLOCK-MAPPING-START token if needed.
- if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
- return false
- }
- }
-
- // Reset any potential simple keys on the current flow level.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // Simple keys are allowed after '?' in the block context.
- parser.simple_key_allowed = parser.flow_level == 0
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the KEY token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_KEY_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the VALUE token.
-func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
-
- simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
-
- // Have we found a simple key?
- if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
- return false
-
- } else if valid {
-
- // Create the KEY token and insert it into the queue.
- token := yaml_token_t{
- typ: yaml_KEY_TOKEN,
- start_mark: simple_key.mark,
- end_mark: simple_key.mark,
- }
- yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
-
- // In the block context, we may need to add the BLOCK-MAPPING-START token.
- if !yaml_parser_roll_indent(parser, simple_key.mark.column,
- simple_key.token_number,
- yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
- return false
- }
-
- // Remove the simple key.
- simple_key.possible = false
- delete(parser.simple_keys_by_tok, simple_key.token_number)
-
- // A simple key cannot follow another simple key.
- parser.simple_key_allowed = false
-
- } else {
- // The ':' indicator follows a complex key.
-
- // In the block context, extra checks are required.
- if parser.flow_level == 0 {
-
- // Check if we are allowed to start a complex value.
- if !parser.simple_key_allowed {
- return yaml_parser_set_scanner_error(parser, "", parser.mark,
- "mapping values are not allowed in this context")
- }
-
- // Add the BLOCK-MAPPING-START token if needed.
- if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
- return false
- }
- }
-
- // Simple keys after ':' are allowed in the block context.
- parser.simple_key_allowed = parser.flow_level == 0
- }
-
- // Consume the token.
- start_mark := parser.mark
- skip(parser)
- end_mark := parser.mark
-
- // Create the VALUE token and append it to the queue.
- token := yaml_token_t{
- typ: yaml_VALUE_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the ALIAS or ANCHOR token.
-func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
- // An anchor or an alias could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow an anchor or an alias.
- parser.simple_key_allowed = false
-
- // Create the ALIAS or ANCHOR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_anchor(parser, &token, typ) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the TAG token.
-func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
- // A tag could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow a tag.
- parser.simple_key_allowed = false
-
- // Create the TAG token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_tag(parser, &token) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
-func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
- // Remove any potential simple keys.
- if !yaml_parser_remove_simple_key(parser) {
- return false
- }
-
- // A simple key may follow a block scalar.
- parser.simple_key_allowed = true
-
- // Create the SCALAR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_block_scalar(parser, &token, literal) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
-func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
- // A plain scalar could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow a flow scalar.
- parser.simple_key_allowed = false
-
- // Create the SCALAR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_flow_scalar(parser, &token, single) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Produce the SCALAR(...,plain) token.
-func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
- // A plain scalar could be a simple key.
- if !yaml_parser_save_simple_key(parser) {
- return false
- }
-
- // A simple key cannot follow a flow scalar.
- parser.simple_key_allowed = false
-
- // Create the SCALAR token and append it to the queue.
- var token yaml_token_t
- if !yaml_parser_scan_plain_scalar(parser, &token) {
- return false
- }
- yaml_insert_token(parser, -1, &token)
- return true
-}
-
-// Eat whitespaces and comments until the next token is found.
-func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
-
- // Until the next token is not found.
- for {
- // Allow the BOM mark to start a line.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
- skip(parser)
- }
-
- // Eat whitespaces.
- // Tabs are allowed:
- // - in the flow context
- // - in the block context, but not at the beginning of the line or
- // after '-', '?', or ':' (complex value).
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Eat a comment until a line break.
- if parser.buffer[parser.buffer_pos] == '#' {
- for !is_breakz(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- }
-
- // If it is a line break, eat it.
- if is_break(parser.buffer, parser.buffer_pos) {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
-
- // In the block context, a new line may start a simple key.
- if parser.flow_level == 0 {
- parser.simple_key_allowed = true
- }
- } else {
- break // We have found a token.
- }
- }
-
- return true
-}
-
-// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
-//
-// Scope:
-// %YAML 1.1 # a comment \n
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-// %TAG !yaml! tag:yaml.org,2002: \n
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//
-func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
- // Eat '%'.
- start_mark := parser.mark
- skip(parser)
-
- // Scan the directive name.
- var name []byte
- if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
- return false
- }
-
- // Is it a YAML directive?
- if bytes.Equal(name, []byte("YAML")) {
- // Scan the VERSION directive value.
- var major, minor int8
- if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
- return false
- }
- end_mark := parser.mark
-
- // Create a VERSION-DIRECTIVE token.
- *token = yaml_token_t{
- typ: yaml_VERSION_DIRECTIVE_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- major: major,
- minor: minor,
- }
-
- // Is it a TAG directive?
- } else if bytes.Equal(name, []byte("TAG")) {
- // Scan the TAG directive value.
- var handle, prefix []byte
- if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
- return false
- }
- end_mark := parser.mark
-
- // Create a TAG-DIRECTIVE token.
- *token = yaml_token_t{
- typ: yaml_TAG_DIRECTIVE_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: handle,
- prefix: prefix,
- }
-
- // Unknown directive.
- } else {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "found unknown directive name")
- return false
- }
-
- // Eat the rest of the line including any comments.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- if parser.buffer[parser.buffer_pos] == '#' {
- for !is_breakz(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- }
-
- // Check if we are at the end of the line.
- if !is_breakz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "did not find expected comment or line break")
- return false
- }
-
- // Eat a line break.
- if is_break(parser.buffer, parser.buffer_pos) {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
- }
-
- return true
-}
-
-// Scan the directive name.
-//
-// Scope:
-// %YAML 1.1 # a comment \n
-// ^^^^
-// %TAG !yaml! tag:yaml.org,2002: \n
-// ^^^
-//
-func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
- // Consume the directive name.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- var s []byte
- for is_alpha(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check if the name is empty.
- if len(s) == 0 {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "could not find expected directive name")
- return false
- }
-
- // Check for an blank character after the name.
- if !is_blankz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a directive",
- start_mark, "found unexpected non-alphabetical character")
- return false
- }
- *name = s
- return true
-}
-
-// Scan the value of VERSION-DIRECTIVE.
-//
-// Scope:
-// %YAML 1.1 # a comment \n
-// ^^^^^^
-func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
- // Eat whitespaces.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Consume the major version number.
- if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
- return false
- }
-
- // Eat '.'.
- if parser.buffer[parser.buffer_pos] != '.' {
- return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
- start_mark, "did not find expected digit or '.' character")
- }
-
- skip(parser)
-
- // Consume the minor version number.
- if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
- return false
- }
- return true
-}
-
-const max_number_length = 2
-
-// Scan the version number of VERSION-DIRECTIVE.
-//
-// Scope:
-// %YAML 1.1 # a comment \n
-// ^
-// %YAML 1.1 # a comment \n
-// ^
-func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
-
- // Repeat while the next character is digit.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- var value, length int8
- for is_digit(parser.buffer, parser.buffer_pos) {
- // Check if the number is too long.
- length++
- if length > max_number_length {
- return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
- start_mark, "found extremely long version number")
- }
- value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check if the number was present.
- if length == 0 {
- return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
- start_mark, "did not find expected version number")
- }
- *number = value
- return true
-}
-
-// Scan the value of a TAG-DIRECTIVE token.
-//
-// Scope:
-// %TAG !yaml! tag:yaml.org,2002: \n
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//
-func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
- var handle_value, prefix_value []byte
-
- // Eat whitespaces.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Scan a handle.
- if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
- return false
- }
-
- // Expect a whitespace.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if !is_blank(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
- start_mark, "did not find expected whitespace")
- return false
- }
-
- // Eat whitespaces.
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Scan a prefix.
- if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
- return false
- }
-
- // Expect a whitespace or line break.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if !is_blankz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
- start_mark, "did not find expected whitespace or line break")
- return false
- }
-
- *handle = handle_value
- *prefix = prefix_value
- return true
-}
-
-func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
- var s []byte
-
- // Eat the indicator character.
- start_mark := parser.mark
- skip(parser)
-
- // Consume the value.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_alpha(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- end_mark := parser.mark
-
- /*
- * Check if length of the anchor is greater than 0 and it is followed by
- * a whitespace character or one of the indicators:
- *
- * '?', ':', ',', ']', '}', '%', '@', '`'.
- */
-
- if len(s) == 0 ||
- !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
- parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
- parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
- parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
- parser.buffer[parser.buffer_pos] == '`') {
- context := "while scanning an alias"
- if typ == yaml_ANCHOR_TOKEN {
- context = "while scanning an anchor"
- }
- yaml_parser_set_scanner_error(parser, context, start_mark,
- "did not find expected alphabetic or numeric character")
- return false
- }
-
- // Create a token.
- *token = yaml_token_t{
- typ: typ,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- }
-
- return true
-}
-
-/*
- * Scan a TAG token.
- */
-
-func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
- var handle, suffix []byte
-
- start_mark := parser.mark
-
- // Check if the tag is in the canonical form.
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- if parser.buffer[parser.buffer_pos+1] == '<' {
- // Keep the handle as ''
-
- // Eat '!<'
- skip(parser)
- skip(parser)
-
- // Consume the tag value.
- if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
- return false
- }
-
- // Check for '>' and eat it.
- if parser.buffer[parser.buffer_pos] != '>' {
- yaml_parser_set_scanner_error(parser, "while scanning a tag",
- start_mark, "did not find the expected '>'")
- return false
- }
-
- skip(parser)
- } else {
- // The tag has either the '!suffix' or the '!handle!suffix' form.
-
- // First, try to scan a handle.
- if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
- return false
- }
-
- // Check if it is, indeed, handle.
- if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
- // Scan the suffix now.
- if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
- return false
- }
- } else {
- // It wasn't a handle after all. Scan the rest of the tag.
- if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
- return false
- }
-
- // Set the handle to '!'.
- handle = []byte{'!'}
-
- // A special case: the '!' tag. Set the handle to '' and the
- // suffix to '!'.
- if len(suffix) == 0 {
- handle, suffix = suffix, handle
- }
- }
- }
-
- // Check the character which ends the tag.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if !is_blankz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a tag",
- start_mark, "did not find expected whitespace or line break")
- return false
- }
-
- end_mark := parser.mark
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_TAG_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: handle,
- suffix: suffix,
- }
- return true
-}
-
-// Scan a tag handle.
-func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
- // Check the initial '!' character.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if parser.buffer[parser.buffer_pos] != '!' {
- yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find expected '!'")
- return false
- }
-
- var s []byte
-
- // Copy the '!' character.
- s = read(parser, s)
-
- // Copy all subsequent alphabetical and numerical characters.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for is_alpha(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check if the trailing character is '!' and copy it.
- if parser.buffer[parser.buffer_pos] == '!' {
- s = read(parser, s)
- } else {
- // It's either the '!' tag or not really a tag handle. If it's a %TAG
- // directive, it's an error. If it's a tag token, it must be a part of URI.
- if directive && string(s) != "!" {
- yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find expected '!'")
- return false
- }
- }
-
- *handle = s
- return true
-}
-
-// Scan a tag.
-func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
- //size_t length = head ? strlen((char *)head) : 0
- var s []byte
- hasTag := len(head) > 0
-
- // Copy the head if needed.
- //
- // Note that we don't copy the leading '!' character.
- if len(head) > 1 {
- s = append(s, head[1:]...)
- }
-
- // Scan the tag.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // The set of characters that may appear in URI is as follows:
- //
- // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
- // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
- // '%'.
- // [Go] Convert this into more reasonable logic.
- for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
- parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
- parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
- parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
- parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
- parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
- parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
- parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
- parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
- parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
- parser.buffer[parser.buffer_pos] == '%' {
- // Check if it is a URI-escape sequence.
- if parser.buffer[parser.buffer_pos] == '%' {
- if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
- return false
- }
- } else {
- s = read(parser, s)
- }
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- hasTag = true
- }
-
- if !hasTag {
- yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find expected tag URI")
- return false
- }
- *uri = s
- return true
-}
-
-// Decode an URI-escape sequence corresponding to a single UTF-8 character.
-func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
-
- // Decode the required number of characters.
- w := 1024
- for w > 0 {
- // Check for a URI-escaped octet.
- if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
- return false
- }
-
- if !(parser.buffer[parser.buffer_pos] == '%' &&
- is_hex(parser.buffer, parser.buffer_pos+1) &&
- is_hex(parser.buffer, parser.buffer_pos+2)) {
- return yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "did not find URI escaped octet")
- }
-
- // Get the octet.
- octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
-
- // If it is the leading octet, determine the length of the UTF-8 sequence.
- if w == 1024 {
- w = width(octet)
- if w == 0 {
- return yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "found an incorrect leading UTF-8 octet")
- }
- } else {
- // Check if the trailing octet is correct.
- if octet&0xC0 != 0x80 {
- return yaml_parser_set_scanner_tag_error(parser, directive,
- start_mark, "found an incorrect trailing UTF-8 octet")
- }
- }
-
- // Copy the octet and move the pointers.
- *s = append(*s, octet)
- skip(parser)
- skip(parser)
- skip(parser)
- w--
- }
- return true
-}
-
-// Scan a block scalar.
-func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
- // Eat the indicator '|' or '>'.
- start_mark := parser.mark
- skip(parser)
-
- // Scan the additional block scalar indicators.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // Check for a chomping indicator.
- var chomping, increment int
- if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
- // Set the chomping method and eat the indicator.
- if parser.buffer[parser.buffer_pos] == '+' {
- chomping = +1
- } else {
- chomping = -1
- }
- skip(parser)
-
- // Check for an indentation indicator.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if is_digit(parser.buffer, parser.buffer_pos) {
- // Check that the indentation is greater than 0.
- if parser.buffer[parser.buffer_pos] == '0' {
- yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "found an indentation indicator equal to 0")
- return false
- }
-
- // Get the indentation level and eat the indicator.
- increment = as_digit(parser.buffer, parser.buffer_pos)
- skip(parser)
- }
-
- } else if is_digit(parser.buffer, parser.buffer_pos) {
- // Do the same as above, but in the opposite order.
-
- if parser.buffer[parser.buffer_pos] == '0' {
- yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "found an indentation indicator equal to 0")
- return false
- }
- increment = as_digit(parser.buffer, parser.buffer_pos)
- skip(parser)
-
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
- if parser.buffer[parser.buffer_pos] == '+' {
- chomping = +1
- } else {
- chomping = -1
- }
- skip(parser)
- }
- }
-
- // Eat whitespaces and comments to the end of the line.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for is_blank(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- if parser.buffer[parser.buffer_pos] == '#' {
- for !is_breakz(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- }
-
- // Check if we are at the end of the line.
- if !is_breakz(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "did not find expected comment or line break")
- return false
- }
-
- // Eat a line break.
- if is_break(parser.buffer, parser.buffer_pos) {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- skip_line(parser)
- }
-
- end_mark := parser.mark
-
- // Set the indentation level if it was specified.
- var indent int
- if increment > 0 {
- if parser.indent >= 0 {
- indent = parser.indent + increment
- } else {
- indent = increment
- }
- }
-
- // Scan the leading line breaks and determine the indentation level if needed.
- var s, leading_break, trailing_breaks []byte
- if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
- return false
- }
-
- // Scan the block scalar content.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- var leading_blank, trailing_blank bool
- for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
- // We are at the beginning of a non-empty line.
-
- // Is it a trailing whitespace?
- trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
-
- // Check if we need to fold the leading line break.
- if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {
- // Do we need to join the lines by space?
- if len(trailing_breaks) == 0 {
- s = append(s, ' ')
- }
- } else {
- s = append(s, leading_break...)
- }
- leading_break = leading_break[:0]
-
- // Append the remaining line breaks.
- s = append(s, trailing_breaks...)
- trailing_breaks = trailing_breaks[:0]
-
- // Is it a leading whitespace?
- leading_blank = is_blank(parser.buffer, parser.buffer_pos)
-
- // Consume the current line.
- for !is_breakz(parser.buffer, parser.buffer_pos) {
- s = read(parser, s)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Consume the line break.
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- leading_break = read_line(parser, leading_break)
-
- // Eat the following indentation spaces and line breaks.
- if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
- return false
- }
- }
-
- // Chomp the tail.
- if chomping != -1 {
- s = append(s, leading_break...)
- }
- if chomping == 1 {
- s = append(s, trailing_breaks...)
- }
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_SCALAR_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- style: yaml_LITERAL_SCALAR_STYLE,
- }
- if !literal {
- token.style = yaml_FOLDED_SCALAR_STYLE
- }
- return true
-}
-
-// Scan indentation spaces and line breaks for a block scalar. Determine the
-// indentation level if needed.
-func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {
- *end_mark = parser.mark
-
- // Eat the indentation spaces and line breaks.
- max_indent := 0
- for {
- // Eat the indentation spaces.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {
- skip(parser)
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
- if parser.mark.column > max_indent {
- max_indent = parser.mark.column
- }
-
- // Check for a tab character messing the indentation.
- if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
- return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
- start_mark, "found a tab character where an indentation space is expected")
- }
-
- // Have we found a non-empty line?
- if !is_break(parser.buffer, parser.buffer_pos) {
- break
- }
-
- // Consume the line break.
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- // [Go] Should really be returning breaks instead.
- *breaks = read_line(parser, *breaks)
- *end_mark = parser.mark
- }
-
- // Determine the indentation level if needed.
- if *indent == 0 {
- *indent = max_indent
- if *indent < parser.indent+1 {
- *indent = parser.indent + 1
- }
- if *indent < 1 {
- *indent = 1
- }
- }
- return true
-}
-
-// Scan a quoted scalar.
-func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
- // Eat the left quote.
- start_mark := parser.mark
- skip(parser)
-
- // Consume the content of the quoted scalar.
- var s, leading_break, trailing_breaks, whitespaces []byte
- for {
- // Check that there are no document indicators at the beginning of the line.
- if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
- return false
- }
-
- if parser.mark.column == 0 &&
- ((parser.buffer[parser.buffer_pos+0] == '-' &&
- parser.buffer[parser.buffer_pos+1] == '-' &&
- parser.buffer[parser.buffer_pos+2] == '-') ||
- (parser.buffer[parser.buffer_pos+0] == '.' &&
- parser.buffer[parser.buffer_pos+1] == '.' &&
- parser.buffer[parser.buffer_pos+2] == '.')) &&
- is_blankz(parser.buffer, parser.buffer_pos+3) {
- yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
- start_mark, "found unexpected document indicator")
- return false
- }
-
- // Check for EOF.
- if is_z(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
- start_mark, "found unexpected end of stream")
- return false
- }
-
- // Consume non-blank characters.
- leading_blanks := false
- for !is_blankz(parser.buffer, parser.buffer_pos) {
- if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
- // Is is an escaped single quote.
- s = append(s, '\'')
- skip(parser)
- skip(parser)
-
- } else if single && parser.buffer[parser.buffer_pos] == '\'' {
- // It is a right single quote.
- break
- } else if !single && parser.buffer[parser.buffer_pos] == '"' {
- // It is a right double quote.
- break
-
- } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
- // It is an escaped line break.
- if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
- return false
- }
- skip(parser)
- skip_line(parser)
- leading_blanks = true
- break
-
- } else if !single && parser.buffer[parser.buffer_pos] == '\\' {
- // It is an escape sequence.
- code_length := 0
-
- // Check the escape character.
- switch parser.buffer[parser.buffer_pos+1] {
- case '0':
- s = append(s, 0)
- case 'a':
- s = append(s, '\x07')
- case 'b':
- s = append(s, '\x08')
- case 't', '\t':
- s = append(s, '\x09')
- case 'n':
- s = append(s, '\x0A')
- case 'v':
- s = append(s, '\x0B')
- case 'f':
- s = append(s, '\x0C')
- case 'r':
- s = append(s, '\x0D')
- case 'e':
- s = append(s, '\x1B')
- case ' ':
- s = append(s, '\x20')
- case '"':
- s = append(s, '"')
- case '\'':
- s = append(s, '\'')
- case '\\':
- s = append(s, '\\')
- case 'N': // NEL (#x85)
- s = append(s, '\xC2')
- s = append(s, '\x85')
- case '_': // #xA0
- s = append(s, '\xC2')
- s = append(s, '\xA0')
- case 'L': // LS (#x2028)
- s = append(s, '\xE2')
- s = append(s, '\x80')
- s = append(s, '\xA8')
- case 'P': // PS (#x2029)
- s = append(s, '\xE2')
- s = append(s, '\x80')
- s = append(s, '\xA9')
- case 'x':
- code_length = 2
- case 'u':
- code_length = 4
- case 'U':
- code_length = 8
- default:
- yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
- start_mark, "found unknown escape character")
- return false
- }
-
- skip(parser)
- skip(parser)
-
- // Consume an arbitrary escape code.
- if code_length > 0 {
- var value int
-
- // Scan the character value.
- if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {
- return false
- }
- for k := 0; k < code_length; k++ {
- if !is_hex(parser.buffer, parser.buffer_pos+k) {
- yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
- start_mark, "did not find expected hexdecimal number")
- return false
- }
- value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
- }
-
- // Check the value and write the character.
- if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
- yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
- start_mark, "found invalid Unicode character escape code")
- return false
- }
- if value <= 0x7F {
- s = append(s, byte(value))
- } else if value <= 0x7FF {
- s = append(s, byte(0xC0+(value>>6)))
- s = append(s, byte(0x80+(value&0x3F)))
- } else if value <= 0xFFFF {
- s = append(s, byte(0xE0+(value>>12)))
- s = append(s, byte(0x80+((value>>6)&0x3F)))
- s = append(s, byte(0x80+(value&0x3F)))
- } else {
- s = append(s, byte(0xF0+(value>>18)))
- s = append(s, byte(0x80+((value>>12)&0x3F)))
- s = append(s, byte(0x80+((value>>6)&0x3F)))
- s = append(s, byte(0x80+(value&0x3F)))
- }
-
- // Advance the pointer.
- for k := 0; k < code_length; k++ {
- skip(parser)
- }
- }
- } else {
- // It is a non-escaped non-blank character.
- s = read(parser, s)
- }
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- }
-
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- // Check if we are at the end of the scalar.
- if single {
- if parser.buffer[parser.buffer_pos] == '\'' {
- break
- }
- } else {
- if parser.buffer[parser.buffer_pos] == '"' {
- break
- }
- }
-
- // Consume blank characters.
- for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
- if is_blank(parser.buffer, parser.buffer_pos) {
- // Consume a space or a tab character.
- if !leading_blanks {
- whitespaces = read(parser, whitespaces)
- } else {
- skip(parser)
- }
- } else {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- // Check if it is a first line break.
- if !leading_blanks {
- whitespaces = whitespaces[:0]
- leading_break = read_line(parser, leading_break)
- leading_blanks = true
- } else {
- trailing_breaks = read_line(parser, trailing_breaks)
- }
- }
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Join the whitespaces or fold line breaks.
- if leading_blanks {
- // Do we need to fold line breaks?
- if len(leading_break) > 0 && leading_break[0] == '\n' {
- if len(trailing_breaks) == 0 {
- s = append(s, ' ')
- } else {
- s = append(s, trailing_breaks...)
- }
- } else {
- s = append(s, leading_break...)
- s = append(s, trailing_breaks...)
- }
- trailing_breaks = trailing_breaks[:0]
- leading_break = leading_break[:0]
- } else {
- s = append(s, whitespaces...)
- whitespaces = whitespaces[:0]
- }
- }
-
- // Eat the right quote.
- skip(parser)
- end_mark := parser.mark
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_SCALAR_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- style: yaml_SINGLE_QUOTED_SCALAR_STYLE,
- }
- if !single {
- token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
- }
- return true
-}
-
-// Scan a plain scalar.
-func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
-
- var s, leading_break, trailing_breaks, whitespaces []byte
- var leading_blanks bool
- var indent = parser.indent + 1
-
- start_mark := parser.mark
- end_mark := parser.mark
-
- // Consume the content of the plain scalar.
- for {
- // Check for a document indicator.
- if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
- return false
- }
- if parser.mark.column == 0 &&
- ((parser.buffer[parser.buffer_pos+0] == '-' &&
- parser.buffer[parser.buffer_pos+1] == '-' &&
- parser.buffer[parser.buffer_pos+2] == '-') ||
- (parser.buffer[parser.buffer_pos+0] == '.' &&
- parser.buffer[parser.buffer_pos+1] == '.' &&
- parser.buffer[parser.buffer_pos+2] == '.')) &&
- is_blankz(parser.buffer, parser.buffer_pos+3) {
- break
- }
-
- // Check for a comment.
- if parser.buffer[parser.buffer_pos] == '#' {
- break
- }
-
- // Consume non-blank characters.
- for !is_blankz(parser.buffer, parser.buffer_pos) {
-
- // Check for indicators that may end a plain scalar.
- if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
- (parser.flow_level > 0 &&
- (parser.buffer[parser.buffer_pos] == ',' ||
- parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
- parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
- parser.buffer[parser.buffer_pos] == '}')) {
- break
- }
-
- // Check if we need to join whitespaces and breaks.
- if leading_blanks || len(whitespaces) > 0 {
- if leading_blanks {
- // Do we need to fold line breaks?
- if leading_break[0] == '\n' {
- if len(trailing_breaks) == 0 {
- s = append(s, ' ')
- } else {
- s = append(s, trailing_breaks...)
- }
- } else {
- s = append(s, leading_break...)
- s = append(s, trailing_breaks...)
- }
- trailing_breaks = trailing_breaks[:0]
- leading_break = leading_break[:0]
- leading_blanks = false
- } else {
- s = append(s, whitespaces...)
- whitespaces = whitespaces[:0]
- }
- }
-
- // Copy the character.
- s = read(parser, s)
-
- end_mark = parser.mark
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
- }
-
- // Is it the end?
- if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
- break
- }
-
- // Consume blank characters.
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
-
- for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
- if is_blank(parser.buffer, parser.buffer_pos) {
-
- // Check for tab characters that abuse indentation.
- if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
- yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
- start_mark, "found a tab character that violates indentation")
- return false
- }
-
- // Consume a space or a tab character.
- if !leading_blanks {
- whitespaces = read(parser, whitespaces)
- } else {
- skip(parser)
- }
- } else {
- if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
- return false
- }
-
- // Check if it is a first line break.
- if !leading_blanks {
- whitespaces = whitespaces[:0]
- leading_break = read_line(parser, leading_break)
- leading_blanks = true
- } else {
- trailing_breaks = read_line(parser, trailing_breaks)
- }
- }
- if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
- return false
- }
- }
-
- // Check indentation level.
- if parser.flow_level == 0 && parser.mark.column < indent {
- break
- }
- }
-
- // Create a token.
- *token = yaml_token_t{
- typ: yaml_SCALAR_TOKEN,
- start_mark: start_mark,
- end_mark: end_mark,
- value: s,
- style: yaml_PLAIN_SCALAR_STYLE,
- }
-
- // Note that we change the 'simple_key_allowed' flag.
- if leading_blanks {
- parser.simple_key_allowed = true
- }
- return true
-}
diff --git a/vendor/go.yaml.in/yaml/v2/sorter.go b/vendor/go.yaml.in/yaml/v2/sorter.go
deleted file mode 100644
index 4c45e660a8..0000000000
--- a/vendor/go.yaml.in/yaml/v2/sorter.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package yaml
-
-import (
- "reflect"
- "unicode"
-)
-
-type keyList []reflect.Value
-
-func (l keyList) Len() int { return len(l) }
-func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
-func (l keyList) Less(i, j int) bool {
- a := l[i]
- b := l[j]
- ak := a.Kind()
- bk := b.Kind()
- for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
- a = a.Elem()
- ak = a.Kind()
- }
- for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
- b = b.Elem()
- bk = b.Kind()
- }
- af, aok := keyFloat(a)
- bf, bok := keyFloat(b)
- if aok && bok {
- if af != bf {
- return af < bf
- }
- if ak != bk {
- return ak < bk
- }
- return numLess(a, b)
- }
- if ak != reflect.String || bk != reflect.String {
- return ak < bk
- }
- ar, br := []rune(a.String()), []rune(b.String())
- for i := 0; i < len(ar) && i < len(br); i++ {
- if ar[i] == br[i] {
- continue
- }
- al := unicode.IsLetter(ar[i])
- bl := unicode.IsLetter(br[i])
- if al && bl {
- return ar[i] < br[i]
- }
- if al || bl {
- return bl
- }
- var ai, bi int
- var an, bn int64
- if ar[i] == '0' || br[i] == '0' {
- for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
- if ar[j] != '0' {
- an = 1
- bn = 1
- break
- }
- }
- }
- for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
- an = an*10 + int64(ar[ai]-'0')
- }
- for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
- bn = bn*10 + int64(br[bi]-'0')
- }
- if an != bn {
- return an < bn
- }
- if ai != bi {
- return ai < bi
- }
- return ar[i] < br[i]
- }
- return len(ar) < len(br)
-}
-
-// keyFloat returns a float value for v if it is a number/bool
-// and whether it is a number/bool or not.
-func keyFloat(v reflect.Value) (f float64, ok bool) {
- switch v.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return float64(v.Int()), true
- case reflect.Float32, reflect.Float64:
- return v.Float(), true
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return float64(v.Uint()), true
- case reflect.Bool:
- if v.Bool() {
- return 1, true
- }
- return 0, true
- }
- return 0, false
-}
-
-// numLess returns whether a < b.
-// a and b must necessarily have the same kind.
-func numLess(a, b reflect.Value) bool {
- switch a.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return a.Int() < b.Int()
- case reflect.Float32, reflect.Float64:
- return a.Float() < b.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return a.Uint() < b.Uint()
- case reflect.Bool:
- return !a.Bool() && b.Bool()
- }
- panic("not a number")
-}
diff --git a/vendor/go.yaml.in/yaml/v2/writerc.go b/vendor/go.yaml.in/yaml/v2/writerc.go
deleted file mode 100644
index a2dde608cb..0000000000
--- a/vendor/go.yaml.in/yaml/v2/writerc.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package yaml
-
-// Set the writer error and return false.
-func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
- emitter.error = yaml_WRITER_ERROR
- emitter.problem = problem
- return false
-}
-
-// Flush the output buffer.
-func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
- if emitter.write_handler == nil {
- panic("write handler not set")
- }
-
- // Check if the buffer is empty.
- if emitter.buffer_pos == 0 {
- return true
- }
-
- if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
- return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
- }
- emitter.buffer_pos = 0
- return true
-}
diff --git a/vendor/go.yaml.in/yaml/v2/yaml.go b/vendor/go.yaml.in/yaml/v2/yaml.go
deleted file mode 100644
index 5248e1263c..0000000000
--- a/vendor/go.yaml.in/yaml/v2/yaml.go
+++ /dev/null
@@ -1,478 +0,0 @@
-// Package yaml implements YAML support for the Go language.
-//
-// Source code and other details for the project are available at GitHub:
-//
-// https://github.com/yaml/go-yaml
-//
-package yaml
-
-import (
- "errors"
- "fmt"
- "io"
- "reflect"
- "strings"
- "sync"
-)
-
-// MapSlice encodes and decodes as a YAML map.
-// The order of keys is preserved when encoding and decoding.
-type MapSlice []MapItem
-
-// MapItem is an item in a MapSlice.
-type MapItem struct {
- Key, Value interface{}
-}
-
-// The Unmarshaler interface may be implemented by types to customize their
-// behavior when being unmarshaled from a YAML document. The UnmarshalYAML
-// method receives a function that may be called to unmarshal the original
-// YAML value into a field or variable. It is safe to call the unmarshal
-// function parameter more than once if necessary.
-type Unmarshaler interface {
- UnmarshalYAML(unmarshal func(interface{}) error) error
-}
-
-// The Marshaler interface may be implemented by types to customize their
-// behavior when being marshaled into a YAML document. The returned value
-// is marshaled in place of the original value implementing Marshaler.
-//
-// If an error is returned by MarshalYAML, the marshaling procedure stops
-// and returns with the provided error.
-type Marshaler interface {
- MarshalYAML() (interface{}, error)
-}
-
-// Unmarshal decodes the first document found within the in byte slice
-// and assigns decoded values into the out value.
-//
-// Maps and pointers (to a struct, string, int, etc) are accepted as out
-// values. If an internal pointer within a struct is not initialized,
-// the yaml package will initialize it if necessary for unmarshalling
-// the provided data. The out parameter must not be nil.
-//
-// The type of the decoded values should be compatible with the respective
-// values in out. If one or more values cannot be decoded due to a type
-// mismatches, decoding continues partially until the end of the YAML
-// content, and a *yaml.TypeError is returned with details for all
-// missed values.
-//
-// Struct fields are only unmarshalled if they are exported (have an
-// upper case first letter), and are unmarshalled using the field name
-// lowercased as the default key. Custom keys may be defined via the
-// "yaml" name in the field tag: the content preceding the first comma
-// is used as the key, and the following comma-separated options are
-// used to tweak the marshalling process (see Marshal).
-// Conflicting names result in a runtime error.
-//
-// For example:
-//
-// type T struct {
-// F int `yaml:"a,omitempty"`
-// B int
-// }
-// var t T
-// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
-//
-// See the documentation of Marshal for the format of tags and a list of
-// supported tag options.
-//
-func Unmarshal(in []byte, out interface{}) (err error) {
- return unmarshal(in, out, false)
-}
-
-// UnmarshalStrict is like Unmarshal except that any fields that are found
-// in the data that do not have corresponding struct members, or mapping
-// keys that are duplicates, will result in
-// an error.
-func UnmarshalStrict(in []byte, out interface{}) (err error) {
- return unmarshal(in, out, true)
-}
-
-// A Decoder reads and decodes YAML values from an input stream.
-type Decoder struct {
- strict bool
- parser *parser
-}
-
-// NewDecoder returns a new decoder that reads from r.
-//
-// The decoder introduces its own buffering and may read
-// data from r beyond the YAML values requested.
-func NewDecoder(r io.Reader) *Decoder {
- return &Decoder{
- parser: newParserFromReader(r),
- }
-}
-
-// SetStrict sets whether strict decoding behaviour is enabled when
-// decoding items in the data (see UnmarshalStrict). By default, decoding is not strict.
-func (dec *Decoder) SetStrict(strict bool) {
- dec.strict = strict
-}
-
-// Decode reads the next YAML-encoded value from its input
-// and stores it in the value pointed to by v.
-//
-// See the documentation for Unmarshal for details about the
-// conversion of YAML into a Go value.
-func (dec *Decoder) Decode(v interface{}) (err error) {
- d := newDecoder(dec.strict)
- defer handleErr(&err)
- node := dec.parser.parse()
- if node == nil {
- return io.EOF
- }
- out := reflect.ValueOf(v)
- if out.Kind() == reflect.Ptr && !out.IsNil() {
- out = out.Elem()
- }
- d.unmarshal(node, out)
- if len(d.terrors) > 0 {
- return &TypeError{d.terrors}
- }
- return nil
-}
-
-func unmarshal(in []byte, out interface{}, strict bool) (err error) {
- defer handleErr(&err)
- d := newDecoder(strict)
- p := newParser(in)
- defer p.destroy()
- node := p.parse()
- if node != nil {
- v := reflect.ValueOf(out)
- if v.Kind() == reflect.Ptr && !v.IsNil() {
- v = v.Elem()
- }
- d.unmarshal(node, v)
- }
- if len(d.terrors) > 0 {
- return &TypeError{d.terrors}
- }
- return nil
-}
-
-// Marshal serializes the value provided into a YAML document. The structure
-// of the generated document will reflect the structure of the value itself.
-// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
-//
-// Struct fields are only marshalled if they are exported (have an upper case
-// first letter), and are marshalled using the field name lowercased as the
-// default key. Custom keys may be defined via the "yaml" name in the field
-// tag: the content preceding the first comma is used as the key, and the
-// following comma-separated options are used to tweak the marshalling process.
-// Conflicting names result in a runtime error.
-//
-// The field tag format accepted is:
-//
-// `(...) yaml:"[][,[,]]" (...)`
-//
-// The following flags are currently supported:
-//
-// omitempty Only include the field if it's not set to the zero
-// value for the type or to empty slices or maps.
-// Zero valued structs will be omitted if all their public
-// fields are zero, unless they implement an IsZero
-// method (see the IsZeroer interface type), in which
-// case the field will be excluded if IsZero returns true.
-//
-// flow Marshal using a flow style (useful for structs,
-// sequences and maps).
-//
-// inline Inline the field, which must be a struct or a map,
-// causing all of its fields or keys to be processed as if
-// they were part of the outer struct. For maps, keys must
-// not conflict with the yaml keys of other struct fields.
-//
-// In addition, if the key is "-", the field is ignored.
-//
-// For example:
-//
-// type T struct {
-// F int `yaml:"a,omitempty"`
-// B int
-// }
-// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
-// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
-//
-func Marshal(in interface{}) (out []byte, err error) {
- defer handleErr(&err)
- e := newEncoder()
- defer e.destroy()
- e.marshalDoc("", reflect.ValueOf(in))
- e.finish()
- out = e.out
- return
-}
-
-// An Encoder writes YAML values to an output stream.
-type Encoder struct {
- encoder *encoder
-}
-
-// NewEncoder returns a new encoder that writes to w.
-// The Encoder should be closed after use to flush all data
-// to w.
-func NewEncoder(w io.Writer) *Encoder {
- return &Encoder{
- encoder: newEncoderWithWriter(w),
- }
-}
-
-// Encode writes the YAML encoding of v to the stream.
-// If multiple items are encoded to the stream, the
-// second and subsequent document will be preceded
-// with a "---" document separator, but the first will not.
-//
-// See the documentation for Marshal for details about the conversion of Go
-// values to YAML.
-func (e *Encoder) Encode(v interface{}) (err error) {
- defer handleErr(&err)
- e.encoder.marshalDoc("", reflect.ValueOf(v))
- return nil
-}
-
-// Close closes the encoder by writing any remaining data.
-// It does not write a stream terminating string "...".
-func (e *Encoder) Close() (err error) {
- defer handleErr(&err)
- e.encoder.finish()
- return nil
-}
-
-func handleErr(err *error) {
- if v := recover(); v != nil {
- if e, ok := v.(yamlError); ok {
- *err = e.err
- } else {
- panic(v)
- }
- }
-}
-
-type yamlError struct {
- err error
-}
-
-func fail(err error) {
- panic(yamlError{err})
-}
-
-func failf(format string, args ...interface{}) {
- panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
-}
-
-// A TypeError is returned by Unmarshal when one or more fields in
-// the YAML document cannot be properly decoded into the requested
-// types. When this error is returned, the value is still
-// unmarshaled partially.
-type TypeError struct {
- Errors []string
-}
-
-func (e *TypeError) Error() string {
- return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
-}
-
-// --------------------------------------------------------------------------
-// Maintain a mapping of keys to structure field indexes
-
-// The code in this section was copied from mgo/bson.
-
-// structInfo holds details for the serialization of fields of
-// a given struct.
-type structInfo struct {
- FieldsMap map[string]fieldInfo
- FieldsList []fieldInfo
-
- // InlineMap is the number of the field in the struct that
- // contains an ,inline map, or -1 if there's none.
- InlineMap int
-}
-
-type fieldInfo struct {
- Key string
- Num int
- OmitEmpty bool
- Flow bool
- // Id holds the unique field identifier, so we can cheaply
- // check for field duplicates without maintaining an extra map.
- Id int
-
- // Inline holds the field index if the field is part of an inlined struct.
- Inline []int
-}
-
-var structMap = make(map[reflect.Type]*structInfo)
-var fieldMapMutex sync.RWMutex
-
-func getStructInfo(st reflect.Type) (*structInfo, error) {
- fieldMapMutex.RLock()
- sinfo, found := structMap[st]
- fieldMapMutex.RUnlock()
- if found {
- return sinfo, nil
- }
-
- n := st.NumField()
- fieldsMap := make(map[string]fieldInfo)
- fieldsList := make([]fieldInfo, 0, n)
- inlineMap := -1
- for i := 0; i != n; i++ {
- field := st.Field(i)
- if field.PkgPath != "" && !field.Anonymous {
- continue // Private field
- }
-
- info := fieldInfo{Num: i}
-
- tag := field.Tag.Get("yaml")
- if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
- tag = string(field.Tag)
- }
- if tag == "-" {
- continue
- }
-
- inline := false
- fields := strings.Split(tag, ",")
- if len(fields) > 1 {
- for _, flag := range fields[1:] {
- switch flag {
- case "omitempty":
- info.OmitEmpty = true
- case "flow":
- info.Flow = true
- case "inline":
- inline = true
- default:
- return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
- }
- }
- tag = fields[0]
- }
-
- if inline {
- switch field.Type.Kind() {
- case reflect.Map:
- if inlineMap >= 0 {
- return nil, errors.New("Multiple ,inline maps in struct " + st.String())
- }
- if field.Type.Key() != reflect.TypeOf("") {
- return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
- }
- inlineMap = info.Num
- case reflect.Struct:
- sinfo, err := getStructInfo(field.Type)
- if err != nil {
- return nil, err
- }
- for _, finfo := range sinfo.FieldsList {
- if _, found := fieldsMap[finfo.Key]; found {
- msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
- return nil, errors.New(msg)
- }
- if finfo.Inline == nil {
- finfo.Inline = []int{i, finfo.Num}
- } else {
- finfo.Inline = append([]int{i}, finfo.Inline...)
- }
- finfo.Id = len(fieldsList)
- fieldsMap[finfo.Key] = finfo
- fieldsList = append(fieldsList, finfo)
- }
- default:
- //return nil, errors.New("Option ,inline needs a struct value or map field")
- return nil, errors.New("Option ,inline needs a struct value field")
- }
- continue
- }
-
- if tag != "" {
- info.Key = tag
- } else {
- info.Key = strings.ToLower(field.Name)
- }
-
- if _, found = fieldsMap[info.Key]; found {
- msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
- return nil, errors.New(msg)
- }
-
- info.Id = len(fieldsList)
- fieldsList = append(fieldsList, info)
- fieldsMap[info.Key] = info
- }
-
- sinfo = &structInfo{
- FieldsMap: fieldsMap,
- FieldsList: fieldsList,
- InlineMap: inlineMap,
- }
-
- fieldMapMutex.Lock()
- structMap[st] = sinfo
- fieldMapMutex.Unlock()
- return sinfo, nil
-}
-
-// IsZeroer is used to check whether an object is zero to
-// determine whether it should be omitted when marshaling
-// with the omitempty flag. One notable implementation
-// is time.Time.
-type IsZeroer interface {
- IsZero() bool
-}
-
-func isZero(v reflect.Value) bool {
- kind := v.Kind()
- if z, ok := v.Interface().(IsZeroer); ok {
- if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
- return true
- }
- return z.IsZero()
- }
- switch kind {
- case reflect.String:
- return len(v.String()) == 0
- case reflect.Interface, reflect.Ptr:
- return v.IsNil()
- case reflect.Slice:
- return v.Len() == 0
- case reflect.Map:
- return v.Len() == 0
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return v.Int() == 0
- case reflect.Float32, reflect.Float64:
- return v.Float() == 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return v.Uint() == 0
- case reflect.Bool:
- return !v.Bool()
- case reflect.Struct:
- vt := v.Type()
- for i := v.NumField() - 1; i >= 0; i-- {
- if vt.Field(i).PkgPath != "" {
- continue // Private field
- }
- if !isZero(v.Field(i)) {
- return false
- }
- }
- return true
- }
- return false
-}
-
-// FutureLineWrap globally disables line wrapping when encoding long strings.
-// This is a temporary and thus deprecated method introduced to faciliate
-// migration towards v3, which offers more control of line lengths on
-// individual encodings, and has a default matching the behavior introduced
-// by this function.
-//
-// The default formatting of v2 was erroneously changed in v2.3.0 and reverted
-// in v2.4.0, at which point this function was introduced to help migration.
-func FutureLineWrap() {
- disableLineWrapping = true
-}
diff --git a/vendor/go.yaml.in/yaml/v2/yamlh.go b/vendor/go.yaml.in/yaml/v2/yamlh.go
deleted file mode 100644
index f6a9c8e34b..0000000000
--- a/vendor/go.yaml.in/yaml/v2/yamlh.go
+++ /dev/null
@@ -1,739 +0,0 @@
-package yaml
-
-import (
- "fmt"
- "io"
-)
-
-// The version directive data.
-type yaml_version_directive_t struct {
- major int8 // The major version number.
- minor int8 // The minor version number.
-}
-
-// The tag directive data.
-type yaml_tag_directive_t struct {
- handle []byte // The tag handle.
- prefix []byte // The tag prefix.
-}
-
-type yaml_encoding_t int
-
-// The stream encoding.
-const (
- // Let the parser choose the encoding.
- yaml_ANY_ENCODING yaml_encoding_t = iota
-
- yaml_UTF8_ENCODING // The default UTF-8 encoding.
- yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
- yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
-)
-
-type yaml_break_t int
-
-// Line break types.
-const (
- // Let the parser choose the break type.
- yaml_ANY_BREAK yaml_break_t = iota
-
- yaml_CR_BREAK // Use CR for line breaks (Mac style).
- yaml_LN_BREAK // Use LN for line breaks (Unix style).
- yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
-)
-
-type yaml_error_type_t int
-
-// Many bad things could happen with the parser and emitter.
-const (
- // No error is produced.
- yaml_NO_ERROR yaml_error_type_t = iota
-
- yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory.
- yaml_READER_ERROR // Cannot read or decode the input stream.
- yaml_SCANNER_ERROR // Cannot scan the input stream.
- yaml_PARSER_ERROR // Cannot parse the input stream.
- yaml_COMPOSER_ERROR // Cannot compose a YAML document.
- yaml_WRITER_ERROR // Cannot write to the output stream.
- yaml_EMITTER_ERROR // Cannot emit a YAML stream.
-)
-
-// The pointer position.
-type yaml_mark_t struct {
- index int // The position index.
- line int // The position line.
- column int // The position column.
-}
-
-// Node Styles
-
-type yaml_style_t int8
-
-type yaml_scalar_style_t yaml_style_t
-
-// Scalar styles.
-const (
- // Let the emitter choose the style.
- yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota
-
- yaml_PLAIN_SCALAR_STYLE // The plain scalar style.
- yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
- yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
- yaml_LITERAL_SCALAR_STYLE // The literal scalar style.
- yaml_FOLDED_SCALAR_STYLE // The folded scalar style.
-)
-
-type yaml_sequence_style_t yaml_style_t
-
-// Sequence styles.
-const (
- // Let the emitter choose the style.
- yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
-
- yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
- yaml_FLOW_SEQUENCE_STYLE // The flow sequence style.
-)
-
-type yaml_mapping_style_t yaml_style_t
-
-// Mapping styles.
-const (
- // Let the emitter choose the style.
- yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
-
- yaml_BLOCK_MAPPING_STYLE // The block mapping style.
- yaml_FLOW_MAPPING_STYLE // The flow mapping style.
-)
-
-// Tokens
-
-type yaml_token_type_t int
-
-// Token types.
-const (
- // An empty token.
- yaml_NO_TOKEN yaml_token_type_t = iota
-
- yaml_STREAM_START_TOKEN // A STREAM-START token.
- yaml_STREAM_END_TOKEN // A STREAM-END token.
-
- yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
- yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token.
- yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token.
- yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token.
-
- yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
- yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token.
- yaml_BLOCK_END_TOKEN // A BLOCK-END token.
-
- yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
- yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token.
- yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token.
- yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token.
-
- yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
- yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token.
- yaml_KEY_TOKEN // A KEY token.
- yaml_VALUE_TOKEN // A VALUE token.
-
- yaml_ALIAS_TOKEN // An ALIAS token.
- yaml_ANCHOR_TOKEN // An ANCHOR token.
- yaml_TAG_TOKEN // A TAG token.
- yaml_SCALAR_TOKEN // A SCALAR token.
-)
-
-func (tt yaml_token_type_t) String() string {
- switch tt {
- case yaml_NO_TOKEN:
- return "yaml_NO_TOKEN"
- case yaml_STREAM_START_TOKEN:
- return "yaml_STREAM_START_TOKEN"
- case yaml_STREAM_END_TOKEN:
- return "yaml_STREAM_END_TOKEN"
- case yaml_VERSION_DIRECTIVE_TOKEN:
- return "yaml_VERSION_DIRECTIVE_TOKEN"
- case yaml_TAG_DIRECTIVE_TOKEN:
- return "yaml_TAG_DIRECTIVE_TOKEN"
- case yaml_DOCUMENT_START_TOKEN:
- return "yaml_DOCUMENT_START_TOKEN"
- case yaml_DOCUMENT_END_TOKEN:
- return "yaml_DOCUMENT_END_TOKEN"
- case yaml_BLOCK_SEQUENCE_START_TOKEN:
- return "yaml_BLOCK_SEQUENCE_START_TOKEN"
- case yaml_BLOCK_MAPPING_START_TOKEN:
- return "yaml_BLOCK_MAPPING_START_TOKEN"
- case yaml_BLOCK_END_TOKEN:
- return "yaml_BLOCK_END_TOKEN"
- case yaml_FLOW_SEQUENCE_START_TOKEN:
- return "yaml_FLOW_SEQUENCE_START_TOKEN"
- case yaml_FLOW_SEQUENCE_END_TOKEN:
- return "yaml_FLOW_SEQUENCE_END_TOKEN"
- case yaml_FLOW_MAPPING_START_TOKEN:
- return "yaml_FLOW_MAPPING_START_TOKEN"
- case yaml_FLOW_MAPPING_END_TOKEN:
- return "yaml_FLOW_MAPPING_END_TOKEN"
- case yaml_BLOCK_ENTRY_TOKEN:
- return "yaml_BLOCK_ENTRY_TOKEN"
- case yaml_FLOW_ENTRY_TOKEN:
- return "yaml_FLOW_ENTRY_TOKEN"
- case yaml_KEY_TOKEN:
- return "yaml_KEY_TOKEN"
- case yaml_VALUE_TOKEN:
- return "yaml_VALUE_TOKEN"
- case yaml_ALIAS_TOKEN:
- return "yaml_ALIAS_TOKEN"
- case yaml_ANCHOR_TOKEN:
- return "yaml_ANCHOR_TOKEN"
- case yaml_TAG_TOKEN:
- return "yaml_TAG_TOKEN"
- case yaml_SCALAR_TOKEN:
- return "yaml_SCALAR_TOKEN"
- }
- return ""
-}
-
-// The token structure.
-type yaml_token_t struct {
- // The token type.
- typ yaml_token_type_t
-
- // The start/end of the token.
- start_mark, end_mark yaml_mark_t
-
- // The stream encoding (for yaml_STREAM_START_TOKEN).
- encoding yaml_encoding_t
-
- // The alias/anchor/scalar value or tag/tag directive handle
- // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
- value []byte
-
- // The tag suffix (for yaml_TAG_TOKEN).
- suffix []byte
-
- // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
- prefix []byte
-
- // The scalar style (for yaml_SCALAR_TOKEN).
- style yaml_scalar_style_t
-
- // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
- major, minor int8
-}
-
-// Events
-
-type yaml_event_type_t int8
-
-// Event types.
-const (
- // An empty event.
- yaml_NO_EVENT yaml_event_type_t = iota
-
- yaml_STREAM_START_EVENT // A STREAM-START event.
- yaml_STREAM_END_EVENT // A STREAM-END event.
- yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
- yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event.
- yaml_ALIAS_EVENT // An ALIAS event.
- yaml_SCALAR_EVENT // A SCALAR event.
- yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
- yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event.
- yaml_MAPPING_START_EVENT // A MAPPING-START event.
- yaml_MAPPING_END_EVENT // A MAPPING-END event.
-)
-
-var eventStrings = []string{
- yaml_NO_EVENT: "none",
- yaml_STREAM_START_EVENT: "stream start",
- yaml_STREAM_END_EVENT: "stream end",
- yaml_DOCUMENT_START_EVENT: "document start",
- yaml_DOCUMENT_END_EVENT: "document end",
- yaml_ALIAS_EVENT: "alias",
- yaml_SCALAR_EVENT: "scalar",
- yaml_SEQUENCE_START_EVENT: "sequence start",
- yaml_SEQUENCE_END_EVENT: "sequence end",
- yaml_MAPPING_START_EVENT: "mapping start",
- yaml_MAPPING_END_EVENT: "mapping end",
-}
-
-func (e yaml_event_type_t) String() string {
- if e < 0 || int(e) >= len(eventStrings) {
- return fmt.Sprintf("unknown event %d", e)
- }
- return eventStrings[e]
-}
-
-// The event structure.
-type yaml_event_t struct {
-
- // The event type.
- typ yaml_event_type_t
-
- // The start and end of the event.
- start_mark, end_mark yaml_mark_t
-
- // The document encoding (for yaml_STREAM_START_EVENT).
- encoding yaml_encoding_t
-
- // The version directive (for yaml_DOCUMENT_START_EVENT).
- version_directive *yaml_version_directive_t
-
- // The list of tag directives (for yaml_DOCUMENT_START_EVENT).
- tag_directives []yaml_tag_directive_t
-
- // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
- anchor []byte
-
- // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
- tag []byte
-
- // The scalar value (for yaml_SCALAR_EVENT).
- value []byte
-
- // Is the document start/end indicator implicit, or the tag optional?
- // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
- implicit bool
-
- // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
- quoted_implicit bool
-
- // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
- style yaml_style_t
-}
-
-func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) }
-func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
-func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) }
-
-// Nodes
-
-const (
- yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null.
- yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false.
- yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values.
- yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values.
- yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values.
- yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
-
- yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
- yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
-
- // Not in original libyaml.
- yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
- yaml_MERGE_TAG = "tag:yaml.org,2002:merge"
-
- yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str.
- yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
- yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map.
-)
-
-type yaml_node_type_t int
-
-// Node types.
-const (
- // An empty node.
- yaml_NO_NODE yaml_node_type_t = iota
-
- yaml_SCALAR_NODE // A scalar node.
- yaml_SEQUENCE_NODE // A sequence node.
- yaml_MAPPING_NODE // A mapping node.
-)
-
-// An element of a sequence node.
-type yaml_node_item_t int
-
-// An element of a mapping node.
-type yaml_node_pair_t struct {
- key int // The key of the element.
- value int // The value of the element.
-}
-
-// The node structure.
-type yaml_node_t struct {
- typ yaml_node_type_t // The node type.
- tag []byte // The node tag.
-
- // The node data.
-
- // The scalar parameters (for yaml_SCALAR_NODE).
- scalar struct {
- value []byte // The scalar value.
- length int // The length of the scalar value.
- style yaml_scalar_style_t // The scalar style.
- }
-
- // The sequence parameters (for YAML_SEQUENCE_NODE).
- sequence struct {
- items_data []yaml_node_item_t // The stack of sequence items.
- style yaml_sequence_style_t // The sequence style.
- }
-
- // The mapping parameters (for yaml_MAPPING_NODE).
- mapping struct {
- pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value).
- pairs_start *yaml_node_pair_t // The beginning of the stack.
- pairs_end *yaml_node_pair_t // The end of the stack.
- pairs_top *yaml_node_pair_t // The top of the stack.
- style yaml_mapping_style_t // The mapping style.
- }
-
- start_mark yaml_mark_t // The beginning of the node.
- end_mark yaml_mark_t // The end of the node.
-
-}
-
-// The document structure.
-type yaml_document_t struct {
-
- // The document nodes.
- nodes []yaml_node_t
-
- // The version directive.
- version_directive *yaml_version_directive_t
-
- // The list of tag directives.
- tag_directives_data []yaml_tag_directive_t
- tag_directives_start int // The beginning of the tag directives list.
- tag_directives_end int // The end of the tag directives list.
-
- start_implicit int // Is the document start indicator implicit?
- end_implicit int // Is the document end indicator implicit?
-
- // The start/end of the document.
- start_mark, end_mark yaml_mark_t
-}
-
-// The prototype of a read handler.
-//
-// The read handler is called when the parser needs to read more bytes from the
-// source. The handler should write not more than size bytes to the buffer.
-// The number of written bytes should be set to the size_read variable.
-//
-// [in,out] data A pointer to an application data specified by
-// yaml_parser_set_input().
-// [out] buffer The buffer to write the data from the source.
-// [in] size The size of the buffer.
-// [out] size_read The actual number of bytes read from the source.
-//
-// On success, the handler should return 1. If the handler failed,
-// the returned value should be 0. On EOF, the handler should set the
-// size_read to 0 and return 1.
-type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
-
-// This structure holds information about a potential simple key.
-type yaml_simple_key_t struct {
- possible bool // Is a simple key possible?
- required bool // Is a simple key required?
- token_number int // The number of the token.
- mark yaml_mark_t // The position mark.
-}
-
-// The states of the parser.
-type yaml_parser_state_t int
-
-const (
- yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
-
- yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document.
- yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START.
- yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document.
- yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END.
- yaml_PARSE_BLOCK_NODE_STATE // Expect a block node.
- yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
- yaml_PARSE_FLOW_NODE_STATE // Expect a flow node.
- yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence.
- yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence.
- yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence.
- yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
- yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key.
- yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value.
- yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
- yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry.
- yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
- yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
- yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
- yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping.
- yaml_PARSE_END_STATE // Expect nothing.
-)
-
-func (ps yaml_parser_state_t) String() string {
- switch ps {
- case yaml_PARSE_STREAM_START_STATE:
- return "yaml_PARSE_STREAM_START_STATE"
- case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
- return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
- case yaml_PARSE_DOCUMENT_START_STATE:
- return "yaml_PARSE_DOCUMENT_START_STATE"
- case yaml_PARSE_DOCUMENT_CONTENT_STATE:
- return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
- case yaml_PARSE_DOCUMENT_END_STATE:
- return "yaml_PARSE_DOCUMENT_END_STATE"
- case yaml_PARSE_BLOCK_NODE_STATE:
- return "yaml_PARSE_BLOCK_NODE_STATE"
- case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
- return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
- case yaml_PARSE_FLOW_NODE_STATE:
- return "yaml_PARSE_FLOW_NODE_STATE"
- case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
- return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
- case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
- return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
- case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
- return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
- case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
- return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
- case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
- return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
- case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
- return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
- case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
- return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
- case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
- return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
- case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
- return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
- case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
- return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
- case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
- return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
- case yaml_PARSE_END_STATE:
- return "yaml_PARSE_END_STATE"
- }
- return ""
-}
-
-// This structure holds aliases data.
-type yaml_alias_data_t struct {
- anchor []byte // The anchor.
- index int // The node id.
- mark yaml_mark_t // The anchor mark.
-}
-
-// The parser structure.
-//
-// All members are internal. Manage the structure using the
-// yaml_parser_ family of functions.
-type yaml_parser_t struct {
-
- // Error handling
-
- error yaml_error_type_t // Error type.
-
- problem string // Error description.
-
- // The byte about which the problem occurred.
- problem_offset int
- problem_value int
- problem_mark yaml_mark_t
-
- // The error context.
- context string
- context_mark yaml_mark_t
-
- // Reader stuff
-
- read_handler yaml_read_handler_t // Read handler.
-
- input_reader io.Reader // File input data.
- input []byte // String input data.
- input_pos int
-
- eof bool // EOF flag
-
- buffer []byte // The working buffer.
- buffer_pos int // The current position of the buffer.
-
- unread int // The number of unread characters in the buffer.
-
- raw_buffer []byte // The raw buffer.
- raw_buffer_pos int // The current position of the buffer.
-
- encoding yaml_encoding_t // The input encoding.
-
- offset int // The offset of the current position (in bytes).
- mark yaml_mark_t // The mark of the current position.
-
- // Scanner stuff
-
- stream_start_produced bool // Have we started to scan the input stream?
- stream_end_produced bool // Have we reached the end of the input stream?
-
- flow_level int // The number of unclosed '[' and '{' indicators.
-
- tokens []yaml_token_t // The tokens queue.
- tokens_head int // The head of the tokens queue.
- tokens_parsed int // The number of tokens fetched from the queue.
- token_available bool // Does the tokens queue contain a token ready for dequeueing.
-
- indent int // The current indentation level.
- indents []int // The indentation levels stack.
-
- simple_key_allowed bool // May a simple key occur at the current position?
- simple_keys []yaml_simple_key_t // The stack of simple keys.
- simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
-
- // Parser stuff
-
- state yaml_parser_state_t // The current parser state.
- states []yaml_parser_state_t // The parser states stack.
- marks []yaml_mark_t // The stack of marks.
- tag_directives []yaml_tag_directive_t // The list of TAG directives.
-
- // Dumper stuff
-
- aliases []yaml_alias_data_t // The alias data.
-
- document *yaml_document_t // The currently parsed document.
-}
-
-// Emitter Definitions
-
-// The prototype of a write handler.
-//
-// The write handler is called when the emitter needs to flush the accumulated
-// characters to the output. The handler should write @a size bytes of the
-// @a buffer to the output.
-//
-// @param[in,out] data A pointer to an application data specified by
-// yaml_emitter_set_output().
-// @param[in] buffer The buffer with bytes to be written.
-// @param[in] size The size of the buffer.
-//
-// @returns On success, the handler should return @c 1. If the handler failed,
-// the returned value should be @c 0.
-//
-type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
-
-type yaml_emitter_state_t int
-
-// The emitter states.
-const (
- // Expect STREAM-START.
- yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
-
- yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END.
- yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END.
- yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document.
- yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END.
- yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence.
- yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence.
- yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
- yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
- yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping.
- yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
- yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence.
- yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence.
- yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
- yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping.
- yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
- yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping.
- yaml_EMIT_END_STATE // Expect nothing.
-)
-
-// The emitter structure.
-//
-// All members are internal. Manage the structure using the @c yaml_emitter_
-// family of functions.
-type yaml_emitter_t struct {
-
- // Error handling
-
- error yaml_error_type_t // Error type.
- problem string // Error description.
-
- // Writer stuff
-
- write_handler yaml_write_handler_t // Write handler.
-
- output_buffer *[]byte // String output data.
- output_writer io.Writer // File output data.
-
- buffer []byte // The working buffer.
- buffer_pos int // The current position of the buffer.
-
- raw_buffer []byte // The raw buffer.
- raw_buffer_pos int // The current position of the buffer.
-
- encoding yaml_encoding_t // The stream encoding.
-
- // Emitter stuff
-
- canonical bool // If the output is in the canonical style?
- best_indent int // The number of indentation spaces.
- best_width int // The preferred width of the output lines.
- unicode bool // Allow unescaped non-ASCII characters?
- line_break yaml_break_t // The preferred line break.
-
- state yaml_emitter_state_t // The current emitter state.
- states []yaml_emitter_state_t // The stack of states.
-
- events []yaml_event_t // The event queue.
- events_head int // The head of the event queue.
-
- indents []int // The stack of indentation levels.
-
- tag_directives []yaml_tag_directive_t // The list of tag directives.
-
- indent int // The current indentation level.
-
- flow_level int // The current flow level.
-
- root_context bool // Is it the document root context?
- sequence_context bool // Is it a sequence context?
- mapping_context bool // Is it a mapping context?
- simple_key_context bool // Is it a simple mapping key context?
-
- line int // The current line.
- column int // The current column.
- whitespace bool // If the last character was a whitespace?
- indention bool // If the last character was an indentation character (' ', '-', '?', ':')?
- open_ended bool // If an explicit document end is required?
-
- // Anchor analysis.
- anchor_data struct {
- anchor []byte // The anchor value.
- alias bool // Is it an alias?
- }
-
- // Tag analysis.
- tag_data struct {
- handle []byte // The tag handle.
- suffix []byte // The tag suffix.
- }
-
- // Scalar analysis.
- scalar_data struct {
- value []byte // The scalar value.
- multiline bool // Does the scalar contain line breaks?
- flow_plain_allowed bool // Can the scalar be expessed in the flow plain style?
- block_plain_allowed bool // Can the scalar be expressed in the block plain style?
- single_quoted_allowed bool // Can the scalar be expressed in the single quoted style?
- block_allowed bool // Can the scalar be expressed in the literal or folded styles?
- style yaml_scalar_style_t // The output style.
- }
-
- // Dumper stuff
-
- opened bool // If the stream was already opened?
- closed bool // If the stream was already closed?
-
- // The information associated with the document nodes.
- anchors *struct {
- references int // The number of references.
- anchor int // The anchor id.
- serialized bool // If the node has been emitted?
- }
-
- last_anchor_id int // The last assigned anchor id.
-
- document *yaml_document_t // The currently emitted document.
-}
diff --git a/vendor/go.yaml.in/yaml/v2/yamlprivateh.go b/vendor/go.yaml.in/yaml/v2/yamlprivateh.go
deleted file mode 100644
index 8110ce3c37..0000000000
--- a/vendor/go.yaml.in/yaml/v2/yamlprivateh.go
+++ /dev/null
@@ -1,173 +0,0 @@
-package yaml
-
-const (
- // The size of the input raw buffer.
- input_raw_buffer_size = 512
-
- // The size of the input buffer.
- // It should be possible to decode the whole raw buffer.
- input_buffer_size = input_raw_buffer_size * 3
-
- // The size of the output buffer.
- output_buffer_size = 128
-
- // The size of the output raw buffer.
- // It should be possible to encode the whole output buffer.
- output_raw_buffer_size = (output_buffer_size*2 + 2)
-
- // The size of other stacks and queues.
- initial_stack_size = 16
- initial_queue_size = 16
- initial_string_size = 16
-)
-
-// Check if the character at the specified position is an alphabetical
-// character, a digit, '_', or '-'.
-func is_alpha(b []byte, i int) bool {
- return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
-}
-
-// Check if the character at the specified position is a digit.
-func is_digit(b []byte, i int) bool {
- return b[i] >= '0' && b[i] <= '9'
-}
-
-// Get the value of a digit.
-func as_digit(b []byte, i int) int {
- return int(b[i]) - '0'
-}
-
-// Check if the character at the specified position is a hex-digit.
-func is_hex(b []byte, i int) bool {
- return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
-}
-
-// Get the value of a hex-digit.
-func as_hex(b []byte, i int) int {
- bi := b[i]
- if bi >= 'A' && bi <= 'F' {
- return int(bi) - 'A' + 10
- }
- if bi >= 'a' && bi <= 'f' {
- return int(bi) - 'a' + 10
- }
- return int(bi) - '0'
-}
-
-// Check if the character is ASCII.
-func is_ascii(b []byte, i int) bool {
- return b[i] <= 0x7F
-}
-
-// Check if the character at the start of the buffer can be printed unescaped.
-func is_printable(b []byte, i int) bool {
- return ((b[i] == 0x0A) || // . == #x0A
- (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
- (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
- (b[i] > 0xC2 && b[i] < 0xED) ||
- (b[i] == 0xED && b[i+1] < 0xA0) ||
- (b[i] == 0xEE) ||
- (b[i] == 0xEF && // #xE000 <= . <= #xFFFD
- !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
- !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
-}
-
-// Check if the character at the specified position is NUL.
-func is_z(b []byte, i int) bool {
- return b[i] == 0x00
-}
-
-// Check if the beginning of the buffer is a BOM.
-func is_bom(b []byte, i int) bool {
- return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
-}
-
-// Check if the character at the specified position is space.
-func is_space(b []byte, i int) bool {
- return b[i] == ' '
-}
-
-// Check if the character at the specified position is tab.
-func is_tab(b []byte, i int) bool {
- return b[i] == '\t'
-}
-
-// Check if the character at the specified position is blank (space or tab).
-func is_blank(b []byte, i int) bool {
- //return is_space(b, i) || is_tab(b, i)
- return b[i] == ' ' || b[i] == '\t'
-}
-
-// Check if the character at the specified position is a line break.
-func is_break(b []byte, i int) bool {
- return (b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
-}
-
-func is_crlf(b []byte, i int) bool {
- return b[i] == '\r' && b[i+1] == '\n'
-}
-
-// Check if the character is a line break or NUL.
-func is_breakz(b []byte, i int) bool {
- //return is_break(b, i) || is_z(b, i)
- return ( // is_break:
- b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
- // is_z:
- b[i] == 0)
-}
-
-// Check if the character is a line break, space, or NUL.
-func is_spacez(b []byte, i int) bool {
- //return is_space(b, i) || is_breakz(b, i)
- return ( // is_space:
- b[i] == ' ' ||
- // is_breakz:
- b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
- b[i] == 0)
-}
-
-// Check if the character is a line break, space, tab, or NUL.
-func is_blankz(b []byte, i int) bool {
- //return is_blank(b, i) || is_breakz(b, i)
- return ( // is_blank:
- b[i] == ' ' || b[i] == '\t' ||
- // is_breakz:
- b[i] == '\r' || // CR (#xD)
- b[i] == '\n' || // LF (#xA)
- b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
- b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
- b[i] == 0)
-}
-
-// Determine the width of the character.
-func width(b byte) int {
- // Don't replace these by a switch without first
- // confirming that it is being inlined.
- if b&0x80 == 0x00 {
- return 1
- }
- if b&0xE0 == 0xC0 {
- return 2
- }
- if b&0xF0 == 0xE0 {
- return 3
- }
- if b&0xF8 == 0xF0 {
- return 4
- }
- return 0
-
-}
diff --git a/vendor/golang.org/x/crypto/argon2/argon2.go b/vendor/golang.org/x/crypto/argon2/argon2.go
index 2b65ec91ac..57ab8371cb 100644
--- a/vendor/golang.org/x/crypto/argon2/argon2.go
+++ b/vendor/golang.org/x/crypto/argon2/argon2.go
@@ -17,8 +17,8 @@
// It uses data-independent memory access, which is preferred for password
// hashing and password-based key derivation. Argon2i requires more passes over
// memory than Argon2id to protect from trade-off attacks. The recommended
-// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive operations are time=3 and to
-// use the maximum available memory.
+// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive
+// operations are time=3 and to use the maximum available memory.
//
// # Argon2id
//
@@ -26,11 +26,14 @@
// Argon2i and Argon2d. It uses data-independent memory access for the first
// half of the first iteration over the memory and data-dependent memory access
// for the rest. Argon2id is side-channel resistant and provides better brute-
-// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
-// parameters for non-interactive operations (taken from [RFC 9106 Section 7.3]) are time=1 and to
-// use the maximum available memory.
+// force cost savings due to time-memory tradeoffs than Argon2i. [RFC 9106
+// Section 4] recommends time=1, memory=2*1024*1024 KiB (2 GiB), and threads=4
+// as the first recommended option. If much less memory is available, it
+// recommends time=3, memory=64*1024 KiB (64 MiB), and threads=4 as the second
+// recommended option.
//
// [argon2-specs.pdf]: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
+// [RFC 9106 Section 4]: https://www.rfc-editor.org/rfc/rfc9106.html#section-4
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
package argon2
@@ -59,9 +62,9 @@ const (
//
// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
//
-// [RFC 9106 Section 7.3] recommends time=3, and memory=32*1024 as a sensible number.
-// If using that amount of memory (32 MB) is not possible in some contexts then
-// the time parameter can be increased to compensate.
+// The example above uses time=3 and memory=32*1024. Argon2i generally
+// requires more passes over memory than Argon2id. If in doubt, prefer IDKey
+// and its Argon2id parameter recommendations.
//
// The time parameter specifies the number of passes over the memory and the
// memory parameter specifies the size of the memory in KiB. For example
@@ -69,8 +72,6 @@ const (
// adjusted to the number of available CPUs. The cost parameters should be
// increased as memory latency and CPU parallelism increases. Remember to get a
// good random salt.
-//
-// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
}
@@ -83,20 +84,20 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3
// For example, you can get a derived key for e.g. AES-256 (which needs a
// 32-byte key) by doing:
//
-// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
+// key := argon2.IDKey([]byte("some password"), salt, 1, 2*1024*1024, 4, 32)
//
-// [RFC 9106 Section 7.3] recommends time=1, and memory=64*1024 as a sensible number.
-// If using that amount of memory (64 MB) is not possible in some contexts then
-// the time parameter can be increased to compensate.
+// The example above uses the first [RFC 9106 Section 4] recommended option.
+// If much less memory is available, the second recommended option is time=3,
+// memory=64*1024 KiB (64 MiB), and threads=4.
//
// The time parameter specifies the number of passes over the memory and the
// memory parameter specifies the size of the memory in KiB. For example
-// memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be
-// adjusted to the numbers of available CPUs. The cost parameters should be
+// memory=2*1024*1024 sets the memory cost to ~2 GiB. The number of threads can
+// be adjusted to the numbers of available CPUs. The cost parameters should be
// increased as memory latency and CPU parallelism increases. Remember to get a
// good random salt.
//
-// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
+// [RFC 9106 Section 4]: https://www.rfc-editor.org/rfc/rfc9106.html#section-4
func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/forward.go b/vendor/golang.org/x/crypto/ssh/agent/forward.go
index fd24ba900d..5e7a0ea40d 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/forward.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/forward.go
@@ -41,6 +41,7 @@ func ForwardToAgent(client *ssh.Client, keyring Agent) error {
continue
}
go ssh.DiscardRequests(reqs)
+ go io.Copy(io.Discard, channel.Stderr())
go func() {
ServeAgent(keyring, channel)
channel.Close()
@@ -72,6 +73,7 @@ func ForwardToRemote(client *ssh.Client, addr string) error {
continue
}
go ssh.DiscardRequests(reqs)
+ go io.Copy(io.Discard, channel.Stderr())
go forwardUnixSocket(channel, addr)
}
}()
diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go
index f05d22fb3d..782c54eb7c 100644
--- a/vendor/golang.org/x/crypto/ssh/agent/server.go
+++ b/vendor/golang.org/x/crypto/ssh/agent/server.go
@@ -304,19 +304,60 @@ func parseEd25519Key(req []byte) (*AddedKey, error) {
return addedKey, nil
}
+func checkDSAParams(param *dsa.Parameters) error {
+ // SSH specifies FIPS 186-2, which only provided a single size
+ // (1024 bits) DSA key. FIPS 186-3 allows for larger key
+ // sizes, which would confuse SSH.
+ if l := param.P.BitLen(); l != 1024 {
+ return fmt.Errorf("ssh: unsupported DSA key size %d", l)
+ }
+
+ // FIPS 186-2 specifies that Q must be exactly 160 bits. We must enforce
+ // this to prevent DoS attacks where an attacker sends a huge Q which makes
+ // verification slow.
+ if l := param.Q.BitLen(); l != 160 {
+ return fmt.Errorf("ssh: unsupported DSA sub-prime size %d", l)
+ }
+
+ // The generator G is an element of the group, so it must be strictly less
+ // than the modulus P.
+ if param.G.Cmp(param.P) >= 0 {
+ return errors.New("ssh: DSA generator larger than modulus")
+ }
+
+ // G must be positive.
+ if param.G.Sign() <= 0 {
+ return errors.New("ssh: DSA generator must be positive")
+ }
+
+ return nil
+}
+
func parseDSAKey(req []byte) (*AddedKey, error) {
var k dsaKeyMsg
if err := ssh.Unmarshal(req, &k); err != nil {
return nil, err
}
+ params := dsa.Parameters{
+ P: k.P,
+ Q: k.Q,
+ G: k.G,
+ }
+ if err := checkDSAParams(¶ms); err != nil {
+ return nil, err
+ }
+
+ // The public value Y must be a non-zero element of the group, i.e. strictly
+ // between 0 and P, to prevent a maliciously oversized Y from slowing
+ // signature operations.
+ if k.Y.Sign() <= 0 || k.Y.Cmp(k.P) >= 0 {
+ return nil, errors.New("agent: DSA public value Y out of range")
+ }
+
priv := &dsa.PrivateKey{
PublicKey: dsa.PublicKey{
- Parameters: dsa.Parameters{
- P: k.P,
- Q: k.Q,
- G: k.G,
- },
- Y: k.Y,
+ Parameters: params,
+ Y: k.Y,
},
X: k.X,
}
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index 334861b7f1..64377715e1 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -182,14 +182,19 @@ func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey
}
hosts := string(keyFields[0])
- // keyFields[1] contains the key type (e.g. “ssh-rsa”).
- // However, that information is duplicated inside the
- // base64-encoded key and so is ignored here.
+ // keyFields[1] contains the key type (e.g. "ssh-rsa"). This information
+ // is duplicated within the base64-encoded key blob. As OpenSSH's
+ // sshkey_read does, we verify that the declared key type matches the
+ // type embedded in the key blob.
+ wantType := string(keyFields[1])
key := bytes.Join(keyFields[2:], []byte(" "))
if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
return "", nil, nil, "", nil, err
}
+ if pubKey.Type() != wantType {
+ return "", nil, nil, "", nil, fmt.Errorf("ssh: known hosts key type mismatch: human-readable type %q, encoded type %q", wantType, pubKey.Type())
+ }
return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
}
@@ -228,10 +233,17 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str
}
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
- return out, comment, options, rest, nil
- } else {
- lastErr = err
+ // The first field contains the declared key type. As OpenSSH's
+ // sshkey_read does, we verify that it matches the type embedded in
+ // the key blob. Without this check, a single-token option (e.g.
+ // "restrict") appearing in the key type position could be silently
+ // discarded along with its intended effect.
+ if string(in[:i]) == out.Type() {
+ return out, comment, options, rest, nil
+ }
+ err = fmt.Errorf("ssh: authorized keys key type mismatch: human-readable type %q, encoded type %q", in[:i], out.Type())
}
+ lastErr = err
// No key type recognised. Maybe there's an options field at
// the beginning.
@@ -271,11 +283,15 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str
}
if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
- options = candidateOptions
- return out, comment, options, rest, nil
- } else {
- lastErr = err
+ // As above, the declared key type (here following the options
+ // field) must match the type embedded in the key blob.
+ if string(in[:i]) == out.Type() {
+ options = candidateOptions
+ return out, comment, options, rest, nil
+ }
+ err = fmt.Errorf("ssh: authorized keys key type mismatch: human-readable type %q, encoded type %q", in[:i], out.Type())
}
+ lastErr = err
in = rest
continue
diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go
index ab22c3d38d..de86f71cf4 100644
--- a/vendor/golang.org/x/crypto/ssh/messages.go
+++ b/vendor/golang.org/x/crypto/ssh/messages.go
@@ -44,7 +44,16 @@ type disconnectMsg struct {
}
func (d *disconnectMsg) Error() string {
- return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
+ return fmt.Sprintf("ssh: disconnect, reason %d: %q", d.Reason, sanitizeString(d.Message))
+}
+
+func sanitizeString(s string) string {
+ return strings.Map(func(r rune) rune {
+ if r == '\t' || (r >= ' ' && r < 0x7f) {
+ return r
+ }
+ return -1
+ }, s)
}
// See RFC 4253, section 7.1.
diff --git a/vendor/golang.org/x/net/bpf/doc.go b/vendor/golang.org/x/net/bpf/doc.go
index 04ec1c8ab5..1ea566b7ff 100644
--- a/vendor/golang.org/x/net/bpf/doc.go
+++ b/vendor/golang.org/x/net/bpf/doc.go
@@ -49,6 +49,13 @@ to extensions, which are essentially calls to kernel utility
functions. Currently, the only extensions supported by this package
are the Linux packet filter extensions.
+# Security Considerations
+
+The implementation of the BPF VM in this package is suitable for
+testing BPF programs. It aims for consistency with other BPF VM
+implementations, but divergence in behavior is not considered a
+security issue.
+
# Examples
This packet filter selects all ARP packets.
diff --git a/vendor/golang.org/x/net/http2/transport_wrap.go b/vendor/golang.org/x/net/http2/transport_wrap.go
index eab2e6b073..534e77ab96 100644
--- a/vendor/golang.org/x/net/http2/transport_wrap.go
+++ b/vendor/golang.org/x/net/http2/transport_wrap.go
@@ -55,7 +55,7 @@ type transportConfig struct {
// Registered is called by net/http.Transport.RegisterProtocol,
// to let us know that it understands the registration mechanism we're using.
func (t transportConfig) Registered(t1 *http.Transport) {
- t.t.t1 = t1
+ t.t.lazyt1 = t1
}
func (t transportConfig) DisableCompression() bool {
@@ -145,29 +145,30 @@ func (t transportConfig) DialFromContext(ctx context.Context, network, address s
type transportInternal struct {
initOnce sync.Once
- t1 *http.Transport
+ lazyt1 *http.Transport
}
-func (t *Transport) init() {
+func (t *Transport) init() *http.Transport {
t.initOnce.Do(func() {
- if t.t1 != nil {
+ if t.lazyt1 != nil {
return
}
t1 := &http.Transport{}
t.configure(t1)
})
+ return t.lazyt1
}
func (t *Transport) configure(t1 *http.Transport) {
t1.RegisterProtocol("http/2", transportConfig{t})
- // tr2.t1 is set by transportConfig.Registered.
- if t.t1 != t1 {
+ // tr2.lazyt1 is set by transportConfig.Registered.
+ if t.lazyt1 != t1 {
panic("http2: net/http does not support this version of x/net/http2")
}
}
func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
- t.init()
+ t1 := t.init()
if req.URL.Scheme == "http" && !t.AllowHTTP {
return nil, errors.New("http2: unencrypted HTTP/2 not enabled")
@@ -188,22 +189,23 @@ func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
ctx := context.WithValue(req.Context(), http2TransportContextKey{}, t)
req = req.WithContext(ctx)
- return t.t1.RoundTrip(req)
+ return t1.RoundTrip(req)
}
func (t *Transport) closeIdleConnections() {
- t.init()
- t.t1.CloseIdleConnections()
+ t1 := t.init()
+ t1.CloseIdleConnections()
}
func (t *Transport) newUserClientConn(c net.Conn) (*ClientConn, error) {
+ t1 := t.init()
// http.Transport's NewClientConn doesn't provide a supported way to create
// a connection from a net.Conn. (This might be useful to add in the future?)
// We're going to craftily sneak one in via the context key, with the
// scheme of "http/2" telling NewClientConn to look for it.
ctx := context.WithValue(context.Background(), netConnContextKey{}, c)
- nhcc, err := t.t1.NewClientConn(ctx, "http/2", "")
+ nhcc, err := t1.NewClientConn(ctx, "http/2", "")
if err != nil {
return nil, err
}
diff --git a/vendor/golang.org/x/net/idna/idna.go b/vendor/golang.org/x/net/idna/idna.go
index 22767125bf..e2f28fed48 100644
--- a/vendor/golang.org/x/net/idna/idna.go
+++ b/vendor/golang.org/x/net/idna/idna.go
@@ -400,7 +400,11 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
// Spec says keep the old label.
continue
}
- if unicode16 && err == nil && len(u) > 0 && isASCII(u) {
+ if err == nil && len(u) > 0 && isASCII(u) {
+ // UTS 43 pre-revision 33 doesn't classify a xn-- label
+ // which contains only ASCII characters as an error,
+ // but that's a specification bug and a security issue.
+ // Always return an error in this case.
err = punyError(enc)
}
isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight
diff --git a/vendor/golang.org/x/sys/cpu/parse.go b/vendor/golang.org/x/sys/cpu/parse.go
index 56a7e1a176..12a99af5c9 100644
--- a/vendor/golang.org/x/sys/cpu/parse.go
+++ b/vendor/golang.org/x/sys/cpu/parse.go
@@ -6,38 +6,50 @@ package cpu
import "strconv"
-// parseRelease parses a dot-separated version number. It follows the semver
-// syntax, but allows the minor and patch versions to be elided.
+// parseRelease parses a dot-separated version number from the prefix
+// of rel. It returns ok=true only if at least the major and minor
+// components were successfully parsed; the patch component is
+// best-effort. Trailing vendor or build suffixes such as
+// "-generic", "+", "_hi3535", or "-rc1" are ignored.
//
// This is a copy of the Go runtime's parseRelease from
-// https://golang.org/cl/209597.
+// https://golang.org/cl/209597, updated in https://golang.org/cl/781800.
func parseRelease(rel string) (major, minor, patch int, ok bool) {
- // Strip anything after a dash or plus.
- for i := range len(rel) {
- if rel[i] == '-' || rel[i] == '+' {
- rel = rel[:i]
- break
+ // next consumes a run of decimal digits from the front of rel,
+ // returning the parsed value. If the digits are followed by a
+ // '.', it is consumed and more is set so the caller knows to
+ // parse another component; otherwise scanning terminates and
+ // the rest of rel is discarded.
+ next := func() (n int, more, ok bool) {
+ i := 0
+ for i < len(rel) && rel[i] >= '0' && rel[i] <= '9' {
+ i++
}
- }
-
- next := func() (int, bool) {
- for i := range len(rel) {
- if rel[i] == '.' {
- ver, err := strconv.Atoi(rel[:i])
- rel = rel[i+1:]
- return ver, err == nil
- }
+ if i == 0 {
+ return 0, false, false
+ }
+ n, err := strconv.Atoi(rel[:i])
+ if err != nil {
+ return 0, false, false
+ }
+ if i < len(rel) && rel[i] == '.' {
+ rel = rel[i+1:]
+ return n, true, true
}
- ver, err := strconv.Atoi(rel)
rel = ""
- return ver, err == nil
+ return n, false, true
+ }
+
+ var more bool
+ if major, more, ok = next(); !ok || !more {
+ return 0, 0, 0, false
}
- if major, ok = next(); !ok || rel == "" {
- return
+ if minor, more, ok = next(); !ok {
+ return 0, 0, 0, false
}
- if minor, ok = next(); !ok || rel == "" {
- return
+ if !more {
+ return major, minor, 0, true
}
- patch, ok = next()
- return
+ patch, _, _ = next()
+ return major, minor, patch, true
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index ce4d7ab1ed..21e2bfa398 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -1874,6 +1874,7 @@ func Dup2(oldfd, newfd int) error {
//sys Dup3(oldfd int, newfd int, flags int) (err error)
//sysnb EpollCreate1(flag int) (fd int, err error)
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD2
//sys Exit(code int) = SYS_EXIT_GROUP
//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_386.go
index 506dafa7b4..210d545c93 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_386.go
@@ -20,7 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
// 64-bit file system and 32-bit uid calls
// (386 default is 32-bit file system and 16-bit uid).
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
index d557cf8de3..a9a52f2319 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
index ecf92bfa2a..54474c20fe 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
@@ -44,7 +44,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
// 64-bit file system and 32-bit uid calls
// (16-bit uid calls are not always supported in newer kernels)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
index 173738077b..e9f30db97d 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
@@ -8,7 +8,6 @@ package unix
import "unsafe"
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
index a3fd1d0b80..6f09ca200a 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
@@ -8,7 +8,6 @@ package unix
import "unsafe"
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
index 70963a95ab..ca3b56597d 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
index c218ebd280..54ba667b1b 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
@@ -13,7 +13,6 @@ import (
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
index e6c48500ca..ce46285902 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
@@ -11,7 +11,6 @@ import (
"unsafe"
)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
index 7286a9aa88..33f7af3804 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
index fc5543c5ff..c658871e30 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
@@ -8,7 +8,6 @@ package unix
import "unsafe"
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
index 66f31210d0..2c8587691b 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
@@ -10,7 +10,6 @@ import (
"unsafe"
)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
index 11d1f16986..4964119af8 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index 9d72a6b73a..5bb51d7ae1 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -1359,6 +1359,7 @@ const (
FAN_UNLIMITED_MARKS = 0x20
FAN_UNLIMITED_QUEUE = 0x10
FD_CLOEXEC = 0x1
+ FD_PIDFS_ROOT = -0x2712
FD_SETSIZE = 0x400
FF0 = 0x0
FIB_RULE_DEV_DETACHED = 0x8
@@ -1970,6 +1971,8 @@ const (
MADV_DONTNEED = 0x4
MADV_DONTNEED_LOCKED = 0x18
MADV_FREE = 0x8
+ MADV_GUARD_INSTALL = 0x66
+ MADV_GUARD_REMOVE = 0x67
MADV_HUGEPAGE = 0xe
MADV_HWPOISON = 0x64
MADV_KEEPONFORK = 0x13
@@ -2114,7 +2117,7 @@ const (
MS_NOSEC = 0x10000000
MS_NOSUID = 0x2
MS_NOSYMFOLLOW = 0x100
- MS_NOUSER = -0x80000000
+ MS_NOUSER = 0x80000000
MS_POSIXACL = 0x10000
MS_PRIVATE = 0x40000
MS_RDONLY = 0x1
@@ -3786,6 +3789,9 @@ const (
TCPOPT_TIMESTAMP = 0x8
TCPOPT_TSTAMP_HDR = 0x101080a
TCPOPT_WINDOW = 0x3
+ TCP_AO_KEYF_EXCLUDE_OPT = 0x2
+ TCP_AO_KEYF_IFINDEX = 0x1
+ TCP_AO_MAXKEYLEN = 0x50
TCP_CC_INFO = 0x1a
TCP_CM_INQ = 0x24
TCP_CONGESTION = 0xd
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
index 80f40e4013..5788c2a58d 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
@@ -700,6 +700,23 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Eventfd(initval uint, flags int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0)
fd = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
index 4def3e9fcb..254f33988f 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64_64, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
index fef2bc8ba9..27c05db1ac 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
index a9fd76a884..840d85bfc3 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
@@ -213,23 +213,6 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
index 4600650280..fe414498b4 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
index c8987d2646..eb358ce05a 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
index 921f430611..c437622f14 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset>>32), uintptr(offset), uintptr(length>>32), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
index 44f067829c..bc4ca25582 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
index e7fa0abf0d..5051435ce7 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
index 8c5125675e..33aa5418a4 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
index 7392fd45e4..3bef8ef1d2 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
index 41180434e6..fc1bd4e2c4 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
index 40c6ce7ae5..d78fe7dabe 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
index 2cfe34adb1..76dcf87d01 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
index 61e6f07097..2cf020f2ba 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
index 834b842042..527637623d 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go
index 6c955cea15..783621561e 100644
--- a/vendor/golang.org/x/sys/windows/security_windows.go
+++ b/vendor/golang.org/x/sys/windows/security_windows.go
@@ -1109,17 +1109,53 @@ const (
)
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
+//
+// Go pointers stored in a TrusteeValue must be pinned using [runtime.Pinner]
+// for the lifetime of the TrusteeValue.
type TrusteeValue uintptr
+// TrusteeValueFromString is unsafe and should not be used.
+//
+// It returns a uintptr containing a reference to newly-allocated memory
+// which will be freed by the garbage collector.
+// There is no way for the caller to safely reference this memory.
+//
+// To create a [TrusteeValue] from a string, use:
+//
+// p, err := windows.UTF16PtrFromString(s)
+// if err != nil {
+// // handle error
+// }
+//
+// // Pin the string for as long as it is used.
+// var pinner runtime.Pinner
+// pinner.Pin(p)
+// defer pinner.Unpin()
+//
+// tv := TrusteeValue(unsafe.Pointer(p))
+//
+// Deprecated: TrusteeValueFromString is unsafe and should not be used.
func TrusteeValueFromString(str string) TrusteeValue {
return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str)))
}
+
+// TrusteeValueFromSID returns a [TrusteeValue] referencing sid.
+//
+// The caller must pin sid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
func TrusteeValueFromSID(sid *SID) TrusteeValue {
return TrusteeValue(unsafe.Pointer(sid))
}
+
+// TrusteeValueFromObjectsAndSid returns a [TrusteeValue] referencing objectsAndSid.
+//
+// The caller must pin objectsAndSid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue {
return TrusteeValue(unsafe.Pointer(objectsAndSid))
}
+
+// TrusteeValueFromObjectsAndName returns a [TrusteeValue] referencing objectsAndName.
+//
+// The caller must pin objectsAndName using a [runtime.Pinner] for the lifetime of the TrusteeValue.
func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue {
return TrusteeValue(unsafe.Pointer(objectsAndName))
}
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 9755bca9fd..e6966b4c32 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -1728,11 +1728,15 @@ func (s *NTUnicodeString) String() string {
// the more common *uint16 string type.
func NewNTString(s string) (*NTString, error) {
var nts NTString
- s8, err := BytePtrFromString(s)
+ s8, err := ByteSliceFromString(s)
if err != nil {
return nil, err
}
- RtlInitString(&nts, s8)
+ // The source string plus its terminating NUL must fit within MAX_USHORT.
+ if len(s8) > MAX_USHORT {
+ return nil, syscall.EINVAL
+ }
+ RtlInitString(&nts, &s8[0])
return &nts, nil
}
diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go
index d2574a73ee..75a50b3165 100644
--- a/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/vendor/golang.org/x/sys/windows/types_windows.go
@@ -169,6 +169,7 @@ const (
FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
+ MAX_USHORT = 0xffff
MAX_PATH = 260
MAX_LONG_PATH = 32768
diff --git a/vendor/golang.org/x/text/unicode/norm/forminfo.go b/vendor/golang.org/x/text/unicode/norm/forminfo.go
index f3a234e5f5..b3cf5d9bde 100644
--- a/vendor/golang.org/x/text/unicode/norm/forminfo.go
+++ b/vendor/golang.org/x/text/unicode/norm/forminfo.go
@@ -121,8 +121,12 @@ func (p Properties) BoundaryAfter() bool {
//
// When all 6 bits are zero, the character is inert, meaning it is never
// influenced by normalization.
+//
+// We set flags to 0x80 (high bit 7 unused in quick check data) to indicate an invalid rune.
type qcInfo uint8
+func (p Properties) isInvalid() bool { return p.flags == 0x80 }
+
func (p Properties) isYesC() bool { return p.flags&0x10 == 0 }
func (p Properties) isYesD() bool { return p.flags&0x4 == 0 }
@@ -247,6 +251,9 @@ func (f Form) PropertiesString(s string) Properties {
// to a Properties. See the comment at the top of the file
// for more information on the format.
func compInfo(v uint16, sz int) Properties {
+ if sz == 0 {
+ return Properties{flags: 0x80, size: 1}
+ }
if v == 0 {
return Properties{size: uint8(sz)}
} else if v >= 0x8000 {
@@ -254,7 +261,7 @@ func compInfo(v uint16, sz int) Properties {
size: uint8(sz),
ccc: uint8(v),
tccc: uint8(v),
- flags: qcInfo(v >> 8),
+ flags: qcInfo(v>>8) & 0x3f,
}
if p.ccc > 0 || p.combinesBackward() {
p.nLead = uint8(p.flags & 0x3)
diff --git a/vendor/golang.org/x/text/unicode/norm/iter.go b/vendor/golang.org/x/text/unicode/norm/iter.go
index 417c6b2689..3cc059224d 100644
--- a/vendor/golang.org/x/text/unicode/norm/iter.go
+++ b/vendor/golang.org/x/text/unicode/norm/iter.go
@@ -376,16 +376,12 @@ func nextComposed(i *Iter) []byte {
goto doNorm
}
prevCC = i.info.tccc
- sz := int(i.info.size)
- if sz == 0 {
- sz = 1 // illegal rune: copy byte-by-byte
- }
- p := outp + sz
+ p := outp + int(i.info.size)
if p > len(i.buf) {
break
}
outp = p
- i.p += sz
+ i.p += int(i.info.size)
if i.p >= i.rb.nsrc {
i.setDone()
break
diff --git a/vendor/golang.org/x/text/unicode/norm/normalize.go b/vendor/golang.org/x/text/unicode/norm/normalize.go
index 4747ad07a8..60b1511caa 100644
--- a/vendor/golang.org/x/text/unicode/norm/normalize.go
+++ b/vendor/golang.org/x/text/unicode/norm/normalize.go
@@ -148,7 +148,7 @@ func (f Form) IsNormalString(s string) bool {
// patched buffer and whether the decomposition is still in progress.
func patchTail(rb *reorderBuffer) bool {
info, p := lastRuneStart(&rb.f, rb.out)
- if p == -1 || info.size == 0 {
+ if p == -1 || info.isInvalid() {
return true
}
end := p + int(info.size)
@@ -225,7 +225,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
}
fd := &rb.f
if doMerge {
- var info Properties
+ info := Properties{flags: 0x80, size: 1} // invalid rune
if p < n {
info = fd.info(src, p)
if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 {
@@ -235,7 +235,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
p = decomposeSegment(rb, p, true)
}
}
- if info.size == 0 {
+ if info.isInvalid() {
rb.doFlush()
// Append incomplete UTF-8 encoding.
return src.appendSlice(rb.out, p, n)
@@ -314,7 +314,7 @@ func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool)
continue
}
info := f.info(src, i)
- if info.size == 0 {
+ if info.isInvalid() {
if atEOF {
// include incomplete runes
return n, true
@@ -379,7 +379,7 @@ func (f Form) firstBoundary(src input, nsrc int) int {
// CGJ insertion points correctly. Luckily it doesn't have to.
for {
info := fd.info(src, i)
- if info.size == 0 {
+ if info.isInvalid() {
return -1
}
if s := ss.next(info); s != ssSuccess {
@@ -424,7 +424,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
}
fd := formTable[f]
info := fd.info(src, 0)
- if info.size == 0 {
+ if info.isInvalid() {
if atEOF {
return 1
}
@@ -435,7 +435,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
for i := int(info.size); i < nsrc; i += int(info.size) {
info = fd.info(src, i)
- if info.size == 0 {
+ if info.isInvalid() {
if atEOF {
return i
}
@@ -465,7 +465,7 @@ func lastBoundary(fd *formInfo, b []byte) int {
if p == -1 {
return -1
}
- if info.size == 0 { // ends with incomplete rune
+ if info.isInvalid() { // ends with incomplete rune
if p == 0 { // starts with incomplete rune
return -1
}
@@ -504,7 +504,7 @@ func lastBoundary(fd *formInfo, b []byte) int {
func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
// Force one character to be consumed.
info := rb.f.info(rb.src, sp)
- if info.size == 0 {
+ if info.isInvalid() {
return 0
}
if s := rb.ss.next(info); s == ssStarter {
@@ -528,7 +528,7 @@ func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
break
}
info = rb.f.info(rb.src, sp)
- if info.size == 0 {
+ if info.isInvalid() {
if !atEOF {
return int(iShortSrc)
}
diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go
index de683684ab..1e5549abe4 100644
--- a/vendor/golang.org/x/tools/go/packages/packages.go
+++ b/vendor/golang.org/x/tools/go/packages/packages.go
@@ -815,6 +815,12 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
needsrc: needsrc,
goVersion: response.GoVersion,
}
+ // Don't trust the driver to respond with duplicate-free
+ // package names (go.dev/issue/63822).
+ if _, ok := ld.pkgs[lpkg.ID]; ok {
+ return nil, fmt.Errorf("%s response contained duplicate packages for ID %q",
+ cond(ld.externalDriver, "go/packages driver", "go list"), lpkg.ID)
+ }
ld.pkgs[lpkg.ID] = lpkg
if rootIndex >= 0 {
initial[rootIndex] = lpkg
@@ -1589,3 +1595,11 @@ func usesExportData(cfg *Config) bool {
}
type unit struct{}
+
+func cond[T any](cond bool, t, f T) T {
+ if cond {
+ return t
+ } else {
+ return f
+ }
+}
diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go
index 4c9450f4ee..686f171d3b 100644
--- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go
+++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go
@@ -823,6 +823,9 @@ func (p *iexporter) doDecl(obj types.Object) {
w.pos(m.Pos())
w.string(m.Name())
sig, _ := m.Type().(*types.Signature)
+ if w.p.version >= iexportVersionGenericMethods && w.bool(sig.TypeParams().Len() > 0) {
+ w.tparamList(obj.Name()+"."+m.Name(), sig.TypeParams(), obj.Pkg())
+ }
// Receiver type parameters are type arguments of the receiver type, so
// their name must be qualified before exporting recv.
diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go
index 1ee4e93549..7b1723e0fc 100644
--- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go
+++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go
@@ -48,13 +48,14 @@ func (r *intReader) uint64() uint64 {
// Keep this in sync with constants in iexport.go.
const (
- iexportVersionGo1_11 = 0
- iexportVersionPosCol = 1
- iexportVersionGo1_18 = 2
- iexportVersionGenerics = 2
- iexportVersion = iexportVersionGenerics
-
- iexportVersionCurrent = 2
+ iexportVersionGo1_11 = 0
+ iexportVersionPosCol = 1
+ iexportVersionGo1_18 = 2
+ iexportVersionGenerics = 2
+ iexportVersionGenericMethods = 3
+ iexportVersion = iexportVersionGenericMethods
+
+ iexportVersionCurrent = 3
)
type ident struct {
@@ -179,9 +180,9 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
version = int64(r.uint64())
switch version {
- case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
+ case iexportVersionGenericMethods, iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
default:
- if version > iexportVersionGo1_18 {
+ if version > iexportVersionGenericMethods {
errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
} else {
errorf("unknown iexport format version %d", version)
@@ -614,6 +615,10 @@ func (r *importReader) obj(pkg *types.Package, name string) {
for n := r.uint64(); n > 0; n-- {
mpos := r.pos()
mname := r.ident()
+ var tpars []*types.TypeParam
+ if r.p.version >= iexportVersionGenericMethods && r.bool() {
+ tpars = r.tparamList()
+ }
recv := r.param(pkg)
// If the receiver has any targs, set those as the
@@ -628,8 +633,7 @@ func (r *importReader) obj(pkg *types.Package, name string) {
rparams[i] = types.Unalias(targs.At(i)).(*types.TypeParam)
}
}
- msig := r.signature(pkg, recv, rparams, nil)
-
+ msig := r.signature(pkg, recv, rparams, tpars)
named.AddMethod(types.NewFunc(mpos, pkg, mname, msig))
}
}
diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go
index d29ecfb017..b99ea6c914 100644
--- a/vendor/golang.org/x/tools/internal/imports/fix.go
+++ b/vendor/golang.org/x/tools/internal/imports/fix.go
@@ -273,7 +273,6 @@ func (p *pass) loadPackageNames(ctx context.Context, imports []*ImportInfo) erro
}
unknown = append(unknown, imp.ImportPath)
}
-
names, err := p.source.LoadPackageNames(ctx, p.srcDir, unknown)
if err != nil {
return err
diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/vendor/golang.org/x/tools/internal/imports/imports.go
index b5f5218b5c..072293835d 100644
--- a/vendor/golang.org/x/tools/internal/imports/imports.go
+++ b/vendor/golang.org/x/tools/internal/imports/imports.go
@@ -74,6 +74,10 @@ func Process(filename string, src []byte, opt *Options) (formatted []byte, err e
// Note that filename's directory influences which imports can be chosen,
// so it is important that filename be accurate.
func FixImports(ctx context.Context, filename string, src []byte, goroot string, logf func(string, ...any), source Source) (fixes []*ImportFix, err error) {
+ if source == nil {
+ // In case someone adds a defective call from a new place
+ panic("source is nil")
+ }
ctx, done := event.Start(ctx, "imports.FixImports")
defer done()
diff --git a/vendor/golang.org/x/tools/internal/stdlib/deps.go b/vendor/golang.org/x/tools/internal/stdlib/deps.go
index dacfc1dfff..0f73c719cd 100644
--- a/vendor/golang.org/x/tools/internal/stdlib/deps.go
+++ b/vendor/golang.org/x/tools/internal/stdlib/deps.go
@@ -12,366 +12,386 @@ type pkginfo struct {
}
var deps = [...]pkginfo{
- {"archive/tar", "\x03q\x03F=\x01\n\x01$\x01\x01\x02\x05\b\x02\x01\x02\x02\r"},
- {"archive/zip", "\x02\x04g\a\x03\x13\x021=\x01+\x05\x01\x0f\x03\x02\x0f\x04"},
- {"bufio", "\x03q\x86\x01D\x15"},
- {"bytes", "t+[\x03\fH\x02\x02"},
+ {"archive/tar", "\x03{\x03F>\x01\n\x01&\x01\x01\x02\x05\b\x02\x01\x02\x02\r"},
+ {"archive/zip", "\x02\x04j\x0e\x03\x12\x022>\x01-\x05\x01\x0f\x03\x02\x0f\x04"},
+ {"bufio", "\x03{\x87\x01F\x15"},
+ {"bytes", "~*]\x03\fJ\x02\x02"},
{"cmp", ""},
- {"compress/bzip2", "\x02\x02\xf6\x01A"},
- {"compress/flate", "\x02r\x03\x83\x01\f\x033\x01\x03"},
- {"compress/gzip", "\x02\x04g\a\x03\x15nU"},
- {"compress/lzw", "\x02r\x03\x83\x01"},
- {"compress/zlib", "\x02\x04g\a\x03\x13\x01o"},
- {"container/heap", "\xbc\x02"},
+ {"compress/bzip2", "\x02\x02\x81\x02C"},
+ {"compress/flate", "\x02|\x03\x84\x01\f\x034\x02\x03"},
+ {"compress/gzip", "\x02\x04j\x0e\x03\x14pW"},
+ {"compress/lzw", "\x02|\x03\x84\x01"},
+ {"compress/zlib", "\x02\x04j\x0e\x03\x12\x01q"},
+ {"container/heap", "\xc9\x02"},
{"container/list", ""},
{"container/ring", ""},
- {"context", "t\\p\x01\x0e"},
- {"crypto", "\x8a\x01pC"},
- {"crypto/aes", "\x10\v\t\x99\x02"},
- {"crypto/cipher", "\x03!\x01\x01 \x12\x1c,Z"},
- {"crypto/des", "\x10\x16 .,\x9d\x01\x03"},
- {"crypto/dsa", "F\x03+\x86\x01\r"},
- {"crypto/ecdh", "\x03\v\r\x10\x04\x17\x03\x0f\x1c\x86\x01"},
- {"crypto/ecdsa", "\x0e\x05\x03\x05\x01\x10\b\v\x06\x01\x03\x0e\x01\x1c\x86\x01\r\x05L\x01"},
- {"crypto/ed25519", "\x0e\x1f\x12\a\x03\b\a\x1cI=C"},
- {"crypto/elliptic", "4@\x86\x01\r9"},
- {"crypto/fips140", "#\x05\x95\x01\x98\x01"},
- {"crypto/hkdf", "0\x15\x01.\x16"},
- {"crypto/hmac", "\x1b\x16\x14\x01\x122"},
- {"crypto/hpke", "\x03\v\x02\x03\x04\x01\f\x01\x05\x1f\x05\a\x01\x01\x1d\x03\x13\x16\x9b\x01\x1c"},
- {"crypto/internal/boring", "\x0e\x02\x0el"},
- {"crypto/internal/boring/bbig", "\x1b\xec\x01N"},
- {"crypto/internal/boring/bcache", "\xc1\x02\x14"},
+ {"context", "~]r\x01\x0e"},
+ {"crypto", "\x93\x01rE"},
+ {"crypto/aes", "\x10\v\n\xa5\x02"},
+ {"crypto/cipher", "\x03\"\x01\x01 \x13$+\\"},
+ {"crypto/des", "\x10\x17 7+\xa1\x01\x03"},
+ {"crypto/dsa", "G\x034\x87\x01\r"},
+ {"crypto/ecdh", "\x03\v\r\x11\x04\x17\x03\x10$\x87\x01"},
+ {"crypto/ecdsa", "\x0e\x05\x03\x05\x01\x11\b\v\x06\x01\x03\x0f\x01$\x87\x01\r\x05O\x01"},
+ {"crypto/ed25519", "\x0e \x12\a\x03\t\a$I>E"},
+ {"crypto/elliptic", "5I\x87\x01\r;"},
+ {"crypto/fips140", "$\x05\x9e\x01\x9b\x01"},
+ {"crypto/hkdf", "1\x15\x017\x15"},
+ {"crypto/hmac", "\x1b\x17\x14\x01\x139"},
+ {"crypto/hpke", "\x03\v\x02\x03\x04\x01\r\x01\x05\x1f\x06\a\x01\x01%\x03\x12\x16\x9f\x01\x1d"},
+ {"crypto/internal/boring", "\x0e\x02\x0eu"},
+ {"crypto/internal/boring/bbig", "\x1b\xf7\x01P"},
+ {"crypto/internal/boring/bcache", "\xce\x02\x14"},
{"crypto/internal/boring/sig", ""},
{"crypto/internal/constanttime", ""},
- {"crypto/internal/cryptotest", "\x03\r\v\b%\x10\x19\x06\x13\x12 \x04\x06\t\x19\x01\x11\x11\x1b\x01\a\x05\b\x03\x05\f"},
- {"crypto/internal/entropy", "K"},
- {"crypto/internal/entropy/v1.0.0", "D0\x95\x018\x14"},
- {"crypto/internal/fips140", "C1\xbf\x01\v\x17"},
- {"crypto/internal/fips140/aes", "\x03 \x03\x02\x14\x05\x01\x01\x05,\x95\x014"},
- {"crypto/internal/fips140/aes/gcm", "#\x01\x02\x02\x02\x12\x05\x01\x06,\x92\x01"},
- {"crypto/internal/fips140/alias", "\xd5\x02"},
- {"crypto/internal/fips140/bigmod", "(\x19\x01\x06,\x95\x01"},
- {"crypto/internal/fips140/check", "#\x0e\a\t\x02\xb7\x01["},
- {"crypto/internal/fips140/check/checktest", "(\x8b\x02\""},
- {"crypto/internal/fips140/drbg", "\x03\x1f\x01\x01\x04\x14\x05\n)\x86\x01\x0f7\x01"},
- {"crypto/internal/fips140/ecdh", "\x03 \x05\x02\n\r3\x86\x01\x0f7"},
- {"crypto/internal/fips140/ecdsa", "\x03 \x04\x01\x02\a\x03\x06:\x16pF"},
- {"crypto/internal/fips140/ed25519", "\x03 \x05\x02\x04\f:\xc9\x01\x03"},
- {"crypto/internal/fips140/edwards25519", "\x1f\t\a\x123\x95\x017"},
- {"crypto/internal/fips140/edwards25519/field", "(\x14\x053\x95\x01"},
- {"crypto/internal/fips140/hkdf", "\x03 \x05\t\a<\x16"},
- {"crypto/internal/fips140/hmac", "\x03 \x15\x01\x01:\x16"},
- {"crypto/internal/fips140/mldsa", "\x03\x1c\x04\x05\x02\x0e\x01\x03\x053\x95\x017"},
- {"crypto/internal/fips140/mlkem", "\x03 \x05\x02\x0f\x03\x053\xcc\x01"},
- {"crypto/internal/fips140/nistec", "\x1f\t\r\f3\x95\x01*\r\x15"},
- {"crypto/internal/fips140/nistec/fiat", "(\x148\x95\x01"},
- {"crypto/internal/fips140/pbkdf2", "\x03 \x05\t\a<\x16"},
- {"crypto/internal/fips140/rsa", "\x03\x1c\x04\x04\x01\x02\x0e\x01\x01\x028\x16pF"},
- {"crypto/internal/fips140/sha256", "\x03 \x1e\x01\x06,\x16\x7f"},
- {"crypto/internal/fips140/sha3", "\x03 \x19\x05\x012\x95\x01L"},
- {"crypto/internal/fips140/sha512", "\x03 \x1e\x01\x06,\x16\x7f"},
- {"crypto/internal/fips140/ssh", "(b"},
- {"crypto/internal/fips140/subtle", "\x1f\a\x1b\xc8\x01"},
- {"crypto/internal/fips140/tls12", "\x03 \x05\t\a\x02:\x16"},
- {"crypto/internal/fips140/tls13", "\x03 \x05\b\b\t3\x16"},
- {"crypto/internal/fips140cache", "\xb3\x02\r'"},
+ {"crypto/internal/cryptotest", "\x03\r\v\t%\x11\x1a\r\x12\x12!\x04\x06\n\x19\x01\x11\x11\x1d\x01\a\x03\x02\b\x02\x01\x05\f"},
+ {"crypto/internal/cryptotest/wycheproof", "\x0e\x12S\x01\f\x01r@\x05\x03\x15\x10"},
+ {"crypto/internal/entropy", "L"},
+ {"crypto/internal/entropy/v1.0.0", "E9\x96\x01:\x14"},
+ {"crypto/internal/fips140", "D:\xc2\x01\v\x17"},
+ {"crypto/internal/fips140/aes", "\x03!\x03\x02\x14\x05\x01\x01\x055\x96\x016"},
+ {"crypto/internal/fips140/aes/gcm", "$\x01\x02\x02\x02\x12\x05\x01\x065\x93\x01"},
+ {"crypto/internal/fips140/alias", "\xe2\x02"},
+ {"crypto/internal/fips140/bigmod", ")\x19\x01\x065\x96\x01"},
+ {"crypto/internal/fips140/check", "$\x0e\a\t\x02\xc1\x01]"},
+ {"crypto/internal/fips140/check/checktest", ")\x97\x02\""},
+ {"crypto/internal/fips140/drbg", "\x03 \x01\x01\x04\x14\x05\n2\x87\x01\x0f9\x01"},
+ {"crypto/internal/fips140/ecdh", "\x03!\x05\x02\n\r<\x87\x01\x0f9"},
+ {"crypto/internal/fips140/ecdsa", "\x03!\x04\x01\x02\a\x03\x06C\x15r\x0f9"},
+ {"crypto/internal/fips140/ed25519", "\x03!\x05\x02\x04\fC\xcc\x01\x03"},
+ {"crypto/internal/fips140/edwards25519", "\x1f\n\a\x12<\x96\x019"},
+ {"crypto/internal/fips140/edwards25519/field", ")\x14\x05<\x96\x01"},
+ {"crypto/internal/fips140/hkdf", "\x03!\x05\t\aE\x15"},
+ {"crypto/internal/fips140/hmac", "\x03!\x15\x01\x01C\x15"},
+ {"crypto/internal/fips140/mldsa", "\x03\x1c\x05\x05\x02\x0e\x01\x03\x05<\x96\x019"},
+ {"crypto/internal/fips140/mlkem", "\x03!\x05\x02\x0f\x03\x05<\xcf\x01"},
+ {"crypto/internal/fips140/nistec", "\x1f\n\r\f<\x96\x01,\r\x15"},
+ {"crypto/internal/fips140/nistec/fiat", ")\x14A\x96\x01"},
+ {"crypto/internal/fips140/pbkdf2", "\x03!\x05\t\aE\x15"},
+ {"crypto/internal/fips140/rsa", "\x03\x1c\x05\x04\x01\x02\x0e\x01\x01\x02A\x15rH"},
+ {"crypto/internal/fips140/sha256", "\x03!\x1e\x01\x065\x15\x81\x01"},
+ {"crypto/internal/fips140/sha3", "\x03!\x19\x05\x01;\x96\x01N"},
+ {"crypto/internal/fips140/sha512", "\x03!\x1e\x01\x065\x15\x81\x01"},
+ {"crypto/internal/fips140/ssh", ")j"},
+ {"crypto/internal/fips140/subtle", "\x1f\b\x1b\xd2\x01"},
+ {"crypto/internal/fips140/tls12", "\x03!\x05\t\a\x02C\x15"},
+ {"crypto/internal/fips140/tls13", "\x03!\x05\b\b\t<\x15"},
+ {"crypto/internal/fips140cache", "\xc0\x02\r."},
{"crypto/internal/fips140deps", ""},
- {"crypto/internal/fips140deps/byteorder", "\xa0\x01"},
- {"crypto/internal/fips140deps/cpu", "\xb5\x01\a"},
- {"crypto/internal/fips140deps/godebug", "\xbd\x01"},
- {"crypto/internal/fips140deps/time", "\xcf\x02"},
- {"crypto/internal/fips140hash", "9\x1d4\xcb\x01"},
- {"crypto/internal/fips140only", "\x17\x13\x0e\x01\x01Pp"},
+ {"crypto/internal/fips140deps/byteorder", "\xa9\x01"},
+ {"crypto/internal/fips140deps/cpu", "\xbe\x01\b"},
+ {"crypto/internal/fips140deps/godebug", "\xc7\x01"},
+ {"crypto/internal/fips140deps/time", "\xe2\x02"},
+ {"crypto/internal/fips140hash", ":\x1e;\xcf\x01"},
+ {"crypto/internal/fips140only", "\x17\x14\x0e\x01\x01Xr"},
{"crypto/internal/fips140test", ""},
- {"crypto/internal/impl", "\xbe\x02"},
- {"crypto/internal/rand", "\x1b\x0f s=["},
- {"crypto/internal/randutil", "\xfa\x01\x12"},
- {"crypto/internal/sysrand", "tq! \r\r\x01\x01\r\x06"},
- {"crypto/internal/sysrand/internal/seccomp", "t"},
- {"crypto/md5", "\x0e8.\x16\x16i"},
- {"crypto/mlkem", "\x0e%"},
- {"crypto/mlkem/mlkemtest", "3\x13\b&"},
- {"crypto/pbkdf2", "6\x0f\x01.\x16"},
- {"crypto/rand", "\x1b\x0f\x1c\x03+\x86\x01\rN"},
- {"crypto/rc4", "& .\xc9\x01"},
- {"crypto/rsa", "\x0e\r\x01\v\x10\x0e\x01\x03\b\a\x1c\x03\x133=\f\x01"},
- {"crypto/sha1", "\x0e\r+\x02,\x16\x16\x15T"},
- {"crypto/sha256", "\x0e\r\x1dR"},
- {"crypto/sha3", "\x0e+Q\xcb\x01"},
- {"crypto/sha512", "\x0e\r\x1fP"},
- {"crypto/subtle", "\x1f\x1d\x9f\x01z"},
- {"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x02\x01\x01\x01\t\x01\x18\x01\x0f\x01\x03\x01\x01\x01\x01\x02\x01\x02\x01\x17\x02\x03\x13\x16\x15\b=\x16\x16\r\b\x01\x01\x01\x02\x01\x0e\x06\x02\x01\x0f"},
- {"crypto/tls/internal/fips140tls", "\x17\xaa\x02"},
- {"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x017\x06\x01\x01\x02\x05\x0e\x06\x02\x02\x03F\x03:\x01\x02\b\x01\x01\x02\a\x10\x05\x01\x06\a\b\x02\x01\x02\x0f\x02\x01\x01\x02\x03\x01"},
- {"crypto/x509/pkix", "j\x06\a\x90\x01H"},
- {"database/sql", "\x03\nQ\x16\x03\x83\x01\v\a\"\x05\b\x02\x03\x01\x0e\x02\x02\x02"},
- {"database/sql/driver", "\rg\x03\xb7\x01\x0f\x12"},
- {"debug/buildinfo", "\x03^\x02\x01\x01\b\a\x03g\x1a\x02\x01+\x0f "},
- {"debug/dwarf", "\x03j\a\x03\x83\x011\x11\x01\x01"},
- {"debug/elf", "\x03\x06W\r\a\x03g\x1b\x01\f \x17\x01\x17"},
- {"debug/gosym", "\x03j\n$\xa1\x01\x01\x01\x02"},
- {"debug/macho", "\x03\x06W\r\ng\x1c,\x17\x01"},
- {"debug/pe", "\x03\x06W\r\a\x03g\x1c,\x17\x01\x17"},
- {"debug/plan9obj", "m\a\x03g\x1c,"},
- {"embed", "t+B\x19\x01T"},
+ {"crypto/internal/impl", "\xcb\x02"},
+ {"crypto/internal/rand", "\x1b\x10 |>]"},
+ {"crypto/internal/randutil", "\x85\x02\x12"},
+ {"crypto/internal/sysrand", "~r!\"\r\r\x01\x01\r\x06"},
+ {"crypto/internal/sysrand/internal/seccomp", "~"},
+ {"crypto/md5", "\x0e97\x15\x16k"},
+ {"crypto/mldsa", "\x0e%K\x87\x01"},
+ {"crypto/mlkem", "\x0e&"},
+ {"crypto/mlkem/mlkemtest", "4\x13\t."},
+ {"crypto/pbkdf2", "7\x0f\x017\x15"},
+ {"crypto/rand", "\x1b\x10\x1c\x034\x87\x01\rP"},
+ {"crypto/rc4", "' 7\xcc\x01"},
+ {"crypto/rsa", "\x0e\r\x01\f\x10\x0e\x01\x03\t\a$\x03\x124>\f\x01"},
+ {"crypto/sha1", "\x0e\r,\x025\x15\x16\x15V"},
+ {"crypto/sha256", "\x0e\r\x1eZ"},
+ {"crypto/sha3", "\x0e,Y\xcf\x01"},
+ {"crypto/sha512", "\x0e\r X"},
+ {"crypto/subtle", "\x1f\x1e\xa9\x01|"},
+ {"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x01\x01\x01\x01\x01\n\x01\x18\x01\x0f\x01\x01\x03\x01\x01\x01\x01\x02\x01\x02\x01\x1f\x02\x03\x12\x16\x15\t>\x16\x18\r\b\x01\x01\x01\x02\x01\x0e\x06\x03\x01\x15"},
+ {"crypto/tls/internal/fips140tls", "\x17\xb7\x02"},
+ {"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x01\x017\x01\x06\x01\x01\x02\x05\x0f\x06\t\x02\x03F\x03;\x01\x02\b\x01\x01\x02\a\x12\x05\x01\x06\a\b\x02\x01\x02\x0f\x02\x01\x01\x02\x04\x01"},
+ {"crypto/x509/pkix", "m\x06\x0e\x91\x019\x11"},
+ {"database/sql", "\x03\nS\x01\x1d\x03\x84\x01\v\a$\x05\b\x02\x03\x01\x0e\x02\x02\x02\x01"},
+ {"database/sql/driver", "\rT\x1d\x03\xba\x01\x0f\x12\a"},
+ {"database/sql/internal", ""},
+ {"debug/buildinfo", "\x03a\x02\x01\x01\b\x0e\x03h\x1a\x02\x01-\x0f "},
+ {"debug/dwarf", "\x03m\x0e\x03\x84\x013\x11\x01\x01"},
+ {"debug/elf", "\x03\x06Z\r\x0e\x03h\x1b\x01\f\"\x17\x01\x17"},
+ {"debug/gosym", "\x03m\x11#\xa5\x01\x01\x01\x02"},
+ {"debug/macho", "\x03\x06Z\r\x11h\x1c.\x17\x01"},
+ {"debug/pe", "\x03\x06Z\r\x0e\x03h\x1c.\x17\x01\x17"},
+ {"debug/plan9obj", "p\x0e\x03h\x1c."},
+ {"embed", "~*D\x19\x01V"},
{"embed/internal/embedtest", ""},
{"encoding", ""},
- {"encoding/ascii85", "\xfa\x01C"},
- {"encoding/asn1", "\x03q\x03g(\x01'\r\x02\x01\x11\x03\x01"},
- {"encoding/base32", "\xfa\x01A\x02"},
- {"encoding/base64", "\xa0\x01ZA\x02"},
- {"encoding/binary", "t\x86\x01\f(\r\x05"},
- {"encoding/csv", "\x02\x01q\x03\x83\x01D\x13\x02"},
- {"encoding/gob", "\x02f\x05\a\x03g\x1c\v\x01\x03\x1d\b\x12\x01\x10\x02"},
- {"encoding/hex", "t\x03\x83\x01A\x03"},
- {"encoding/json", "\x03\x01d\x04\b\x03\x83\x01\f(\r\x02\x01\x02\x11\x01\x01\x02"},
- {"encoding/pem", "\x03i\b\x86\x01A\x03"},
- {"encoding/xml", "\x02\x01e\f\x03\x83\x014\x05\n\x01\x02\x11\x02"},
- {"errors", "\xd0\x01\x85\x01"},
- {"expvar", "qLA\b\v\x15\r\b\x02\x03\x01\x12"},
- {"flag", "h\f\x03\x83\x01,\b\x05\b\x02\x01\x11"},
- {"fmt", "tF'\x19\f \b\r\x02\x03\x13"},
- {"go/ast", "\x03\x01s\x0f\x01s\x03)\b\r\x02\x01\x13\x02"},
- {"go/build", "\x02\x01q\x03\x01\x02\x02\b\x02\x01\x17\x1f\x04\x02\b\x1c\x13\x01+\x01\x04\x01\a\b\x02\x01\x13\x02\x02"},
- {"go/build/constraint", "t\xc9\x01\x01\x13\x02"},
- {"go/constant", "w\x10\x7f\x01\x024\x01\x02\x13"},
- {"go/doc", "\x04s\x01\x05\n=61\x10\x02\x01\x13\x02"},
- {"go/doc/comment", "\x03t\xc4\x01\x01\x01\x01\x13\x02"},
- {"go/format", "\x03t\x01\f\x01\x02sD"},
- {"go/importer", "y\a\x01\x02\x04\x01r9"},
- {"go/internal/gccgoimporter", "\x02\x01^\x13\x03\x04\f\x01p\x02,\x01\x05\x11\x01\r\b"},
- {"go/internal/gcimporter", "\x02u\x10\x010\x05\r0,\x15\x03\x02"},
- {"go/internal/scannerhooks", "\x87\x01"},
- {"go/internal/srcimporter", "w\x01\x01\v\x03\x01r,\x01\x05\x12\x02\x15"},
- {"go/parser", "\x03q\x03\x01\x02\b\x04\x01s\x01+\x06\x12"},
- {"go/printer", "w\x01\x02\x03\ns\f \x15\x02\x01\x02\f\x05\x02"},
- {"go/scanner", "\x03t\v\x05s2\x10\x01\x14\x02"},
- {"go/token", "\x04s\x86\x01>\x02\x03\x01\x10\x02"},
- {"go/types", "\x03\x01\x06j\x03\x01\x03\t\x03\x024\x063\x04\x03\t \x06\a\b\x01\x01\x01\x02\x01\x10\x02\x02"},
- {"go/version", "\xc2\x01|"},
- {"hash", "\xfa\x01"},
- {"hash/adler32", "t\x16\x16"},
- {"hash/crc32", "t\x16\x16\x15\x8b\x01\x01\x14"},
- {"hash/crc64", "t\x16\x16\xa0\x01"},
- {"hash/fnv", "t\x16\x16i"},
- {"hash/maphash", "\x8a\x01\x11<~"},
- {"html", "\xbe\x02\x02\x13"},
- {"html/template", "\x03n\x06\x19-=\x01\n!\x05\x01\x02\x03\f\x01\x02\r\x01\x03\x02"},
- {"image", "\x02r\x1fg\x0f4\x03\x01"},
+ {"encoding/ascii85", "\x85\x02E"},
+ {"encoding/asn1", "\x03{\x03h(\x01)\r\x02\x01\x11\x03\x01"},
+ {"encoding/base32", "\x85\x02C\x02"},
+ {"encoding/base64", "\xa9\x01\\C\x02"},
+ {"encoding/binary", "~\x87\x01\f*\r\x05"},
+ {"encoding/csv", "\x02\x01{\x03\x84\x01F\x13\x02"},
+ {"encoding/gob", "\x02i\x05\x0e\x03h\x1c\v\x01\x03\x1f\b\x12\x01\x10\x02"},
+ {"encoding/hex", "~\x03\x84\x01C\x03"},
+ {"encoding/json", "\x03\x01g\n\x01\x01\x02\x01\x01\x03\x03\x84\x016\x0f\x01"},
+ {"encoding/json/internal", "~"},
+ {"encoding/json/internal/jsonflags", "u"},
+ {"encoding/json/internal/jsonopts", "u\x01"},
+ {"encoding/json/internal/jsontest", "\x03f\x15\x03\x83\x01\x01\x012\b\b\x03\x02\x0f"},
+ {"encoding/json/internal/jsonwire", "\x04r\b\x87\x01\f7\x02\x01\x13\x01\x01"},
+ {"encoding/json/jsontext", "\x03r\x01\x01\x02\x05\x87\x01\x03\t\x034\x02\x01\x02\x13"},
+ {"encoding/json/v2", "\x03\x01g\x03\x01\x01\x03\x02\x01\x01\x02\x01\x04\x03\x84\x01\f\x03'\r\x02\x01\x02\x0f\x02\x02"},
+ {"encoding/pem", "\x03l\x0f\x87\x01C\x03"},
+ {"encoding/xml", "\x02\x01h\x13\x03\x84\x016\x05\n\x01\x02\x11\x02"},
+ {"errors", "\xdb\x01\x87\x01"},
+ {"expvar", "tSB\b\v\x17\r\b\x02\x03\x01\x12"},
+ {"flag", "k\x13\x03\x84\x01.\b\x05\b\x02\x01\x11"},
+ {"fmt", "~E)\x19\f\"\b\r\x02\x03\x13"},
+ {"go/ast", "\x03\x01}\x0e\x01u\x03+\b\r\x02\x01\x13\x02"},
+ {"go/build", "\x02\x01{\x03\x01\x02\x02\a\x02\x01\x17 \x04\x02\t\x1c\x13\x01-\x01\x04\x01\a\b\x02\x01\x13\x02\x02"},
+ {"go/build/constraint", "~\xcc\x01\x01\x13\x02"},
+ {"go/constant", "\x81\x01\x0f\x81\x01\x01\x026\x01\x02\x13"},
+ {"go/doc", "\x04}\x01\x05\t>73\x10\x02\x01\x13\x02"},
+ {"go/doc/comment", "\x03~\xc7\x01\x01\x01\x01\x13\x02"},
+ {"go/format", "\x03~\x01\v\x01\x02uF"},
+ {"go/importer", "\x83\x01\a\x01\x01\x04\x01t;"},
+ {"go/internal/gccgoimporter", "\x02\x01a\x1a\x03\x04\v\x01r\x02.\x01\x05\x11\x01\r\b"},
+ {"go/internal/gcimporter", "\x02\x7f\x0f\x010\x140.\x15\x03\x02"},
+ {"go/internal/srcimporter", "\x81\x01\x01\x01\n\x03\x01t.\x01\x05\x12\x02\x15"},
+ {"go/parser", "\x03{\x03\x01\x02\v\x01u\x01-\x06\x12"},
+ {"go/printer", "\x81\x01\x01\x02\x03\tu\f\"\x15\x02\x01\x02\f\x05\x02"},
+ {"go/scanner", "\x03~\x0fu4\x10\x01\x14\x02"},
+ {"go/token", "\x04}\x87\x01@\x02\x03\x01\x10\x02"},
+ {"go/types", "\x03\x01\x06t\x03\x01\x03\b\x03\x02\x0654\x04\x03\t\"\x06\a\b\x01\x01\x01\x02\x01\x10\x02\x02"},
+ {"go/version", "\xcc\x01\x7f"},
+ {"hash", "\x85\x02"},
+ {"hash/adler32", "~\x15\x16"},
+ {"hash/crc32", "~\x15\x16\x15\x8f\x01\x01\x14"},
+ {"hash/crc64", "~\x15\x16\xa4\x01"},
+ {"hash/fnv", "~\x15\x16k"},
+ {"hash/maphash", "\x93\x01\x11>\x80\x01"},
+ {"html", "\xcb\x02\x02\x13"},
+ {"html/template", "\x03q\r\x18.>\x01\n#\x05\x01\x02\x03\n\x02\x01\x02\r\x01\x03\x02"},
+ {"image", "\x02|\x1ei\x0f6\x03\x01"},
{"image/color", ""},
- {"image/color/palette", "\x93\x01"},
- {"image/draw", "\x92\x01\x01\x04"},
- {"image/gif", "\x02\x01\x05l\x03\x1b\x01\x01\x01\vZ\x0f"},
- {"image/internal/imageutil", "\x92\x01"},
- {"image/jpeg", "\x02r\x1e\x01\x04c"},
- {"image/png", "\x02\ad\n\x13\x02\x06\x01gC"},
- {"index/suffixarray", "\x03j\a\x86\x01\f+\n\x01"},
- {"internal/abi", "\xbc\x01\x99\x01"},
- {"internal/asan", "\xd5\x02"},
- {"internal/bisect", "\xb3\x02\r\x01"},
- {"internal/buildcfg", "wHg\x06\x02\x05\n\x01"},
- {"internal/bytealg", "\xb5\x01\xa0\x01"},
+ {"image/color/palette", "\x9c\x01"},
+ {"image/draw", "\x9b\x01\x01\x04"},
+ {"image/gif", "\x02\x01\x05v\x03\x1a\x01\x01\x01\v\\\x0f"},
+ {"image/internal/imageutil", "\x9b\x01"},
+ {"image/jpeg", "\x02|\x1d\x01\x04e"},
+ {"image/png", "\x02\ag\x11\x12\x02\x06\x01iE"},
+ {"index/suffixarray", "\x03m\x0e\x87\x01\f-\n\x01"},
+ {"internal/abi", "\xc6\x01\x9c\x01"},
+ {"internal/asan", "\xe2\x02"},
+ {"internal/bisect", "\xc0\x02\r\x01"},
+ {"internal/buildcfg", "\x81\x01Hj\x06\x02\x05\n\x01"},
+ {"internal/bytealg", "\xbe\x01\xa4\x01"},
{"internal/byteorder", ""},
{"internal/cfg", ""},
- {"internal/cgrouptest", "w[T\x06\x0f\x02\x01\x04\x01"},
- {"internal/chacha8rand", "\xa0\x01\x15\a\x99\x01"},
+ {"internal/cgrouptest", "\x81\x01\\V\x06\x0f\x02\x01\x04\x01"},
+ {"internal/chacha8rand", "\xa9\x01\x15\b\x9c\x01"},
{"internal/copyright", ""},
{"internal/coverage", ""},
{"internal/coverage/calloc", ""},
- {"internal/coverage/cfile", "q\x06\x17\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01\"\x02',\x06\a\n\x01\x03\x0e\x06"},
- {"internal/coverage/cformat", "\x04s.\x04Q\v6\x01\x02\x0e"},
- {"internal/coverage/cmerge", "w.a"},
- {"internal/coverage/decodecounter", "m\n.\v\x02H,\x17\x18"},
- {"internal/coverage/decodemeta", "\x02k\n\x17\x17\v\x02H,"},
- {"internal/coverage/encodecounter", "\x02k\n.\f\x01\x02F\v!\x15"},
- {"internal/coverage/encodemeta", "\x02\x01j\n\x13\x04\x17\r\x02F,/"},
- {"internal/coverage/pods", "\x04s.\x81\x01\x06\x05\n\x02\x01"},
- {"internal/coverage/rtcov", "\xd5\x02"},
- {"internal/coverage/slicereader", "m\n\x83\x01["},
- {"internal/coverage/slicewriter", "w\x83\x01"},
- {"internal/coverage/stringtab", "w9\x04F"},
+ {"internal/coverage/cfile", "t\r\x16\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01$\x02'.\x06\a\n\x01\x03\x0e\x06"},
+ {"internal/coverage/cformat", "\x04}-\x04S\v8\x01\x02\x0e"},
+ {"internal/coverage/cmerge", "\x81\x01-c"},
+ {"internal/coverage/decodecounter", "p\x11-\v\x02J.\x17\x18"},
+ {"internal/coverage/decodemeta", "\x02n\x11\x16\x17\v\x02J."},
+ {"internal/coverage/encodecounter", "\x02n\x11-\f\x01\x02H\v#\x15"},
+ {"internal/coverage/encodemeta", "\x02\x01m\x11\x12\x04\x17\r\x02H./"},
+ {"internal/coverage/pods", "\x04}-\x85\x01\x06\x05\n\x02\x01"},
+ {"internal/coverage/rtcov", "\xe2\x02"},
+ {"internal/coverage/slicereader", "p\x11\x84\x01]"},
+ {"internal/coverage/slicewriter", "\x81\x01\x84\x01"},
+ {"internal/coverage/stringtab", "\x81\x018\x04H"},
{"internal/coverage/test", ""},
{"internal/coverage/uleb128", ""},
- {"internal/cpu", "\xd5\x02"},
- {"internal/dag", "\x04s\xc4\x01\x03"},
- {"internal/diff", "\x03t\xc5\x01\x02"},
- {"internal/exportdata", "\x02\x01q\x03\x02e\x1c,\x01\x05\x11\x01\x02"},
- {"internal/filepathlite", "t+B\x1a@"},
- {"internal/fmtsort", "\x04\xaa\x02\r"},
- {"internal/fuzz", "\x03\nH\x18\x04\x03\x03\x01\f\x036=\f\x03\x1d\x01\x05\x02\x05\n\x01\x02\x01\x01\r\x04\x02"},
+ {"internal/cpu", "\xe2\x02"},
+ {"internal/dag", "\x04}\xc7\x01\x03"},
+ {"internal/diff", "\x03~\xc8\x01\x02"},
+ {"internal/exportdata", "\x02\x01{\x03\x02f\x1c.\x01\x05\x11\x01\x02"},
+ {"internal/filepathlite", "~*D\x1aB"},
+ {"internal/fmtsort", "\x04\xb7\x02\r"},
+ {"internal/fuzz", "\x03\nJ\x19\x04\n\x03\x01\v\x037>\f\x03\x1f\x01\x05\x02\x05\n\x01\x02\x01\x01\r\x04\x02"},
+ {"internal/gate", "\r"},
{"internal/goarch", ""},
- {"internal/godebug", "\x9d\x01!\x82\x01\x01\x14"},
+ {"internal/godebug", "\xa6\x01\"\x85\x01\x01\x14"},
{"internal/godebugs", ""},
{"internal/goexperiment", ""},
{"internal/goos", ""},
- {"internal/goroot", "\xa6\x02\x01\x05\x12\x02"},
+ {"internal/goroot", "\xb3\x02\x01\x05\x12\x02"},
{"internal/gover", "\x04"},
{"internal/goversion", ""},
- {"internal/lazyregexp", "\xa6\x02\v\r\x02"},
- {"internal/lazytemplate", "\xfa\x01,\x18\x02\r"},
- {"internal/msan", "\xd5\x02"},
+ {"internal/lazyregexp", "\xb3\x02\v\r\x02"},
+ {"internal/lazytemplate", "\x85\x02.\x18\x02\r"},
+ {"internal/msan", "\xe2\x02"},
+ {"internal/nettest", "\x03\nqG@\f\n\x12\x06\x15\x05\x0f"},
{"internal/nettrace", ""},
- {"internal/obscuretestdata", "l\x8e\x01,"},
- {"internal/oserror", "t"},
- {"internal/pkgbits", "\x03R\x18\a\x03\x04\fs\r\x1f\r\n\x01"},
+ {"internal/obscuretestdata", "o\x96\x01."},
+ {"internal/oserror", "~"},
+ {"internal/pkgbits", "\x03T\x19\x0e\x03\x04\vu\r!\r\n\x01"},
{"internal/platform", ""},
- {"internal/poll", "tl\x05\x159\r\x01\x01\r\x06"},
- {"internal/profile", "\x03\x04m\x03\x83\x017\n\x01\x01\x01\x11"},
+ {"internal/poll", "~m\x05\x15;\r\x01\x01\r\x06"},
+ {"internal/profile", "\x03\x04w\x03\x84\x019\n\x01\x01\x01\x11"},
{"internal/profilerecord", ""},
- {"internal/race", "\x9b\x01\xba\x01"},
- {"internal/reflectlite", "\x9b\x01!;<\""},
- {"internal/runtime/atomic", "\xbc\x01\x99\x01"},
- {"internal/runtime/cgroup", "\x9f\x01=\x04u"},
- {"internal/runtime/exithook", "\xd1\x01\x84\x01"},
- {"internal/runtime/gc", "\xbc\x01"},
- {"internal/runtime/gc/internal/gen", "\nc\n\x18k\x04\v\x1d\b\x10\x02"},
- {"internal/runtime/gc/scan", "\xb5\x01\a\x18\az"},
- {"internal/runtime/maps", "\x9b\x01\x01 \n\t\t\x03z"},
- {"internal/runtime/math", "\xbc\x01"},
+ {"internal/race", "\xa4\x01\xbe\x01"},
+ {"internal/reflectlite", "\xa4\x01\"<>\""},
+ {"internal/runtime/atomic", "\xc6\x01\x9c\x01"},
+ {"internal/runtime/cgroup", "\xa8\x01?\x04w"},
+ {"internal/runtime/exithook", "\xdc\x01\x86\x01"},
+ {"internal/runtime/gc", "\xc6\x01"},
+ {"internal/runtime/gc/internal/gen", "\nf\x11\x17m\x04\v\x1f\b\x10\x02"},
+ {"internal/runtime/gc/scan", "\xbe\x01\b\x19\a|"},
+ {"internal/runtime/maps", "\xa4\x01\x01\x04\x15\b\x03\a\n\t\x03.N"},
+ {"internal/runtime/math", "\xc6\x01"},
{"internal/runtime/pprof/label", ""},
{"internal/runtime/startlinetest", ""},
- {"internal/runtime/sys", "\xbc\x01\x04"},
- {"internal/runtime/syscall/linux", "\xbc\x01\x99\x01"},
+ {"internal/runtime/sys", "\xc6\x01\x04"},
+ {"internal/runtime/syscall/linux", "\xc6\x01\x9c\x01"},
{"internal/runtime/wasitest", ""},
- {"internal/saferio", "\xfa\x01["},
- {"internal/singleflight", "\xc0\x02"},
- {"internal/strconv", "\x89\x02L"},
- {"internal/stringslite", "\x9f\x01\xb6\x01"},
- {"internal/sync", "\x9b\x01!\x13r\x14"},
- {"internal/synctest", "\x9b\x01\xba\x01"},
- {"internal/syscall/execenv", "\xc2\x02"},
- {"internal/syscall/unix", "\xb3\x02\x0e\x01\x13"},
- {"internal/sysinfo", "\x02\x01\xb2\x01E,\x18\x02"},
+ {"internal/saferio", "\x85\x02]"},
+ {"internal/singleflight", "\xcd\x02"},
+ {"internal/strconv", "\x94\x02N"},
+ {"internal/stringslite", "\xa8\x01\xba\x01"},
+ {"internal/sync", "\xa4\x01\"\x14t\x14"},
+ {"internal/synctest", "\xa4\x01\xbe\x01"},
+ {"internal/syscall/execenv", "\xcf\x02"},
+ {"internal/syscall/unix", "\xeb\x01U\x0e\x01\x13"},
+ {"internal/sysinfo", "\x02\x01\xbb\x01G.\x18\x02"},
{"internal/syslist", ""},
- {"internal/testenv", "\x03\ng\x02\x01*\x1b\x0f0+\x01\x05\a\n\x01\x02\x02\x01\f"},
- {"internal/testhash", "\x03\x87\x01p\x118\f"},
- {"internal/testlog", "\xc0\x02\x01\x14"},
- {"internal/testpty", "t\x03\xaf\x01"},
- {"internal/trace", "\x02\x01\x01\x06c\a\x03w\x03\x03\x06\x03\t+\n\x01\x01\x01\x11\x06"},
- {"internal/trace/internal/testgen", "\x03j\nu\x03\x02\x03\x011\v\r\x11"},
- {"internal/trace/internal/tracev1", "\x03\x01i\a\x03}\x06\f5\x01"},
- {"internal/trace/raw", "\x02k\nz\x03\x06C\x01\x13"},
- {"internal/trace/testtrace", "\x02\x01q\x03q\x04\x03\x05\x01\x05,\v\x02\b\x02\x01\x05"},
+ {"internal/testenv", "\x03\nq\x02\x01)\x1c\x100-\x01\x05\a\n\x01\x02\x02\x01\f"},
+ {"internal/testhash", "\x03\x90\x01r\x11:\f"},
+ {"internal/testlog", "\xcd\x02\x01\x14"},
+ {"internal/testpty", "~\x03\xb2\x01"},
+ {"internal/trace", "\x02\x01\x01\x06f\x0e\x03x\x03\x03\x06\x03\t-\n\x01\x01\x01\x11\x06"},
+ {"internal/trace/internal/testgen", "\x03m\x11v\x03\x02\x03\x013\v\r\x11"},
+ {"internal/trace/internal/tracev1", "\x03\x01l\x0e\x03~\x06\f7\x01"},
+ {"internal/trace/raw", "\x02n\x11{\x03\x06E\x01\x13"},
+ {"internal/trace/testtrace", "\x02\x01{\x03r\x04\x03\x05\x01\x05.\v\x02\b\x02\x01\x05"},
{"internal/trace/tracev2", ""},
- {"internal/trace/traceviewer", "\x02d\v\x06\x1a<\x1f\a\a\x04\b\v\x15\x01\x05\a\n\x01\x02\x0f"},
+ {"internal/trace/traceviewer", "\x02g\v\r\x19>\x1f\a\a\x04\b\v\x17\x01\x05\a\n\x01\x02\x0f"},
{"internal/trace/traceviewer/format", ""},
- {"internal/trace/version", "wz\t"},
- {"internal/txtar", "\x03t\xaf\x01\x18"},
- {"internal/types/errors", "\xbd\x02"},
- {"internal/unsafeheader", "\xd5\x02"},
- {"internal/xcoff", "`\r\a\x03g\x1c,\x17\x01"},
- {"internal/zstd", "m\a\x03\x83\x01\x0f"},
- {"io", "t\xcc\x01"},
- {"io/fs", "t+*11\x10\x14\x04"},
- {"io/ioutil", "\xfa\x01\x01+\x15\x03"},
- {"iter", "\xcf\x01d\""},
- {"log", "w\x83\x01\x05'\r\r\x01\x0e"},
+ {"internal/trace/version", "\x81\x01{\t"},
+ {"internal/txtar", "\x03~\xb2\x01\x18"},
+ {"internal/types/errors", "\xca\x02"},
+ {"internal/unsafeheader", "\xe2\x02"},
+ {"internal/xcoff", "c\r\x0e\x03h\x1c.\x17\x01"},
+ {"internal/zstd", "p\x0e\x03\x84\x01\x0f"},
+ {"io", "~\xcf\x01"},
+ {"io/fs", "~*,13\x10\x14\x04"},
+ {"io/ioutil", "\x85\x02\x01-\x15\x03"},
+ {"iter", "\xda\x01f\""},
+ {"log", "\x81\x01\x84\x01\x05)\r\r\x01\x0e"},
{"log/internal", ""},
- {"log/slog", "\x03\n[\t\x03\x03\x83\x01\x04\x01\x02\x02\x03(\x05\b\x02\x01\x02\x01\x0e\x02\x02\x02"},
+ {"log/slog", "\x03\n^\t\n\x03H<\x04\x01\x02\x02\x03*\x05\b\x02\x01\x02\x01\x0e\x02\x02\x02"},
{"log/slog/internal", ""},
- {"log/slog/internal/benchmarks", "\rg\x03\x83\x01\x06\x03:\x12"},
- {"log/slog/internal/buffer", "\xc0\x02"},
- {"log/syslog", "t\x03\x87\x01\x12\x16\x18\x02\x0f"},
- {"maps", "\xfd\x01X"},
- {"math", "\xb5\x01TL"},
- {"math/big", "\x03q\x03)\x15E\f\x03\x020\x02\x01\x02\x15"},
- {"math/big/internal/asmgen", "\x03\x01s\x92\x012\x03"},
- {"math/bits", "\xd5\x02"},
- {"math/cmplx", "\x86\x02\x03"},
- {"math/rand", "\xbd\x01I:\x01\x14"},
- {"math/rand/v2", "t,\x03c\x03L"},
- {"mime", "\x02\x01i\b\x03\x83\x01\v!\x15\x03\x02\x11\x02"},
- {"mime/multipart", "\x02\x01N#\x03F=\v\x01\a\x02\x15\x02\x06\x0f\x02\x01\x17"},
- {"mime/quotedprintable", "\x02\x01t\x83\x01"},
- {"net", "\x04\tg+\x1e\n\x05\x13\x01\x01\x04\x15\x01%\x06\r\b\x05\x01\x01\r\x06\a"},
- {"net/http", "\x02\x01\x03\x01\x04\x02D\b\x13\x01\a\x03F=\x01\x03\a\x01\x03\x02\x02\x01\x02\x06\x02\x01\x01\n\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\x0e\x02\x02\x02\b\x01\x01\x01"},
- {"net/http/cgi", "\x02W\x1b\x03\x83\x01\x04\a\v\x01\x13\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x11\x0e"},
- {"net/http/cookiejar", "\x04p\x03\x99\x01\x01\b\a\x05\x16\x03\x02\x0f\x04"},
- {"net/http/fcgi", "\x02\x01\n`\a\x03\x83\x01\x16\x01\x01\x14\x18\x02\x0f"},
- {"net/http/httptest", "\x02\x01\nL\x02\x1b\x01\x83\x01\x04\x12\x01\n\t\x02\x17\x01\x02\x0f\x0e"},
- {"net/http/httptrace", "\rLnI\x14\n!"},
- {"net/http/httputil", "\x02\x01\ng\x03\x83\x01\x04\x0f\x03\x01\x05\x02\x01\v\x01\x19\x02\x01\x0e\x0e"},
- {"net/http/internal", "\x02\x01q\x03\x83\x01"},
- {"net/http/internal/ascii", "\xbe\x02\x13"},
- {"net/http/internal/httpcommon", "\rg\x03\x9f\x01\x0e\x01\x17\x01\x01\x02\x1d\x02"},
- {"net/http/internal/testcert", "\xbe\x02"},
- {"net/http/pprof", "\x02\x01\nj\x19-\x02\x0e-\x04\x13\x14\x01\r\x04\x03\x01\x02\x01\x11"},
+ {"log/slog/internal/benchmarks", "\rq\x03\x84\x01\x06\x03<\x12"},
+ {"log/slog/internal/buffer", "\xcd\x02"},
+ {"log/syslog", "~\x03\x88\x01\x12\x18\x18\x02\x0f"},
+ {"maps", "\x88\x02Z"},
+ {"math", "\xbe\x01VN"},
+ {"math/big", "\x03{\x03(\x15G\f\x03\x022\x02\x01\x02\x15"},
+ {"math/big/internal/asmgen", "\x03\x01}\x93\x014\x03"},
+ {"math/bits", "\xe2\x02"},
+ {"math/cmplx", "\x91\x02\x03"},
+ {"math/rand", "\xc7\x01J<\x01\x14"},
+ {"math/rand/v2", "~+\x03e\x03N"},
+ {"mime", "\x02\x01l\x0f\x03\x84\x01\v#\x15\x03\x02\x11\x02"},
+ {"mime/multipart", "\x02\x01P+\x03F>\v\x01\a\x02\x17\x02\x06\x0f\x02\x01\x17"},
+ {"mime/quotedprintable", "\x02\x01~\x84\x01"},
+ {"net", "\x04\tq*\x1f\v\x05\x13\x01\x01\x04\x15\x01'\x06\r\b\x05\x01\x01\r\x06\t"},
+ {"net/http", "\x02\x01\x03\x01\x04\x02N\x14\x0f\x03F>\x01\x03\a\x01\x06\x01\x01\x02\x06\x02\x01\x01\f\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\x0e\x02\x02\x02\n\x01\x03"},
+ {"net/http/cgi", "\x02Y#\x03\x84\x01\x04\a\v\x01\x15\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x11\x10"},
+ {"net/http/cookiejar", "\x04z\x03\x9a\x01\x01\b\t\x05\x16\x03\x02\x0f\x04"},
+ {"net/http/fcgi", "\x02\x01\nc\x0e\x03\x84\x01\x16\x01\x01\x16\x18\x02\x0f"},
+ {"net/http/httptest", "\x02\x01\nN\x02#\x01P4\x04\x12\x01\f\t\x02\r\n\x01\x02\x03\f\x06\n"},
+ {"net/http/httptrace", "\rNwI\x16+"},
+ {"net/http/httputil", "\x02\x01\nq\x03F>\x04\x0f\x03\x01\x05\x02\x01\r\x01\x19\x02\x01\x0e\x10"},
+ {"net/http/internal", "\x02\x01m\x0e\x03\x84\x01"},
+ {"net/http/internal/ascii", "\xcb\x02\x13"},
+ {"net/http/internal/http2", "\x02\x01\x03\x01\x06F\b\x15\x0e\x03\x84\x01\x01\x03\b\x03\x02\x03\x02\x06\x02\x03\x01\n\x01\x01\b\x05\b\x02\x01\x02\x01\x0e\x10\x02\x02"},
+ {"net/http/internal/httpcommon", "\rq\x03\xa0\x01\x10\x01\x17\x01\x01\x02\x1f\x02"},
+ {"net/http/internal/httpsfv", "\xc8\x02\x02\x01\x11\x04"},
+ {"net/http/internal/testcert", "\xcb\x02"},
+ {"net/http/pprof", "\x02\x01\nt\x18.\x11-\x04\x13\x16\x01\r\x04\x03\x01\x02\x01\x11"},
{"net/internal/cgotest", ""},
- {"net/internal/socktest", "w\xc9\x01\x02"},
- {"net/mail", "\x02r\x03\x83\x01\x04\x0f\x03\x14\x1a\x02\x0f\x04"},
- {"net/netip", "\x04p+\x01f\x034\x17"},
- {"net/rpc", "\x02m\x05\x03\x10\ni\x04\x12\x01\x1d\r\x03\x02"},
- {"net/rpc/jsonrpc", "q\x03\x03\x83\x01\x16\x11\x1f"},
- {"net/smtp", "\x194\f\x13\b\x03\x83\x01\x16\x14\x1a"},
- {"net/textproto", "\x02\x01q\x03\x83\x01\f\n-\x01\x02\x15"},
- {"net/url", "t\x03Fc\v\x10\x02\x01\x17"},
- {"os", "t+\x01\x19\x03\x10\x14\x01\x03\x01\x05\x10\x018\b\x05\x01\x01\r\x06"},
- {"os/exec", "\x03\ngI'\x01\x15\x01+\x06\a\n\x01\x03\x01\r"},
- {"os/exec/internal/fdtest", "\xc2\x02"},
- {"os/signal", "\r\x99\x02\x15\x05\x02"},
- {"os/user", "\x02\x01q\x03\x83\x01,\r\n\x01\x02"},
- {"path", "t+\xb4\x01"},
- {"path/filepath", "t+\x1aB+\r\b\x03\x04\x11"},
- {"plugin", "t"},
- {"reflect", "t'\x04\x1d\x13\b\x04\x05\x17\x06\t-\n\x03\x11\x02\x02"},
+ {"net/internal/socktest", "\x81\x01\xcc\x01\x02"},
+ {"net/mail", "\x02|\x03\x84\x01\x04\x0f\x03\x16\x1a\x02\x0f\x04"},
+ {"net/netip", "\x04z*\x01h\x036\x17"},
+ {"net/rpc", "\x02p\f\x03\x0f\nk\x04\x12\x01\x1f\r\x03\x02"},
+ {"net/rpc/jsonrpc", "t\n\x03\x84\x01\x16\x13\x1f"},
+ {"net/smtp", "\x195\r\x14\x0f\x03\x84\x01\x16\x16\x1a"},
+ {"net/textproto", "\x02\x01{\x03\x84\x01\f\n/\x01\x02\x15"},
+ {"net/url", "~\x03Ff\v\x10\x02\x01\x17"},
+ {"os", "~*\x01\x19\x04\x11\x14\x01\x03\x01\x05\x10\x01:\b\x05\x01\x01\r\x06"},
+ {"os/exec", "\x03\nqI(\x01\x15\x01-\x06\a\n\x01\x03\x01\r"},
+ {"os/exec/internal/fdtest", "\xcf\x02"},
+ {"os/signal", "\r\xa6\x02\x15\x05\x02"},
+ {"os/user", "\x02\x01{\x03\x84\x01.\r\n\x01\x02"},
+ {"path", "~*\xb8\x01"},
+ {"path/filepath", "~*\x1aD-\r\b\x03\x04\x11"},
+ {"plugin", "~"},
+ {"reflect", "~&\x04\x1e\x03\x11\b\x04\x05\x17\x06\t/\n\x03\x11\x02\x02"},
{"reflect/internal/example1", ""},
{"reflect/internal/example2", ""},
- {"regexp", "\x03\xf7\x018\t\x02\x01\x02\x11\x02"},
- {"regexp/syntax", "\xbb\x02\x01\x01\x01\x02\x11\x02"},
- {"runtime", "\x9b\x01\x04\x01\x03\f\x06\a\x02\x01\x01\x0e\x03\x01\x01\x01\x02\x01\x01\x01\x02\x01\x04\x01\x10\x18L"},
- {"runtime/coverage", "\xa7\x01S"},
- {"runtime/debug", "wUZ\r\b\x02\x01\x11\x06"},
- {"runtime/metrics", "\xbe\x01H-\""},
- {"runtime/pprof", "\x02\x01\x01\x03\x06`\a\x03$$\x0f\v!\f \r\b\x01\x01\x01\x02\x02\n\x03\x06"},
- {"runtime/race", "\xb9\x02"},
+ {"regexp", "\x03\x82\x02\x037\t\x02\x01\x02\x11\x02"},
+ {"regexp/syntax", "\xc8\x02\x01\x01\x01\x02\x11\x02"},
+ {"runtime", "\xa4\x01\x04\x01\x03\f\x06\b\x02\x01\x01\x0f\x03\x01\x01\x01\x02\x01\x01\x01\x02\x01\x04\x01\x10\x18N"},
+ {"runtime/coverage", "\xb0\x01U"},
+ {"runtime/debug", "\x81\x01V\\\r\b\x02\x01\x11\x06"},
+ {"runtime/metrics", "\xc8\x01I/\""},
+ {"runtime/pprof", "\x02\x01\x01\x03\x06c\x0e\x03#5\v!\f\"\r\b\x01\x01\x01\x02\x02\n\x03\x06"},
+ {"runtime/race", "\xc6\x02"},
{"runtime/race/internal/amd64v1", ""},
- {"runtime/trace", "\rg\x03z\t9\b\x05\x01\x0e\x06"},
- {"slices", "\x04\xf9\x01\fL"},
- {"sort", "\xd0\x0192"},
- {"strconv", "t+A\x01r"},
- {"strings", "t'\x04B\x19\x03\f7\x11\x02\x02"},
+ {"runtime/trace", "\rq\x03{\t;\b\x05\x01\x0e\x06"},
+ {"slices", "\x04\x84\x02\fN"},
+ {"sort", "\xdb\x0194"},
+ {"strconv", "~*C\x01t"},
+ {"strings", "~&\x04D\x19\x03\f9\x11\x02\x02"},
{"structs", ""},
- {"sync", "\xcf\x01\x13\x01P\x0e\x14"},
- {"sync/atomic", "\xd5\x02"},
- {"syscall", "t(\x03\x01\x1c\n\x03\x06\r\x04S\b\x05\x01\x14"},
- {"testing", "\x03\ng\x02\x01X\x17\x14\f\x05\x1b\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\x0e\x02\x04"},
- {"testing/cryptotest", "QOZ\x124\x03\x12"},
- {"testing/fstest", "t\x03\x83\x01\x01\n&\x10\x03\t\b"},
- {"testing/internal/testdeps", "\x02\v\xae\x01/\x10,\x03\x05\x03\x06\a\x02\x0f"},
- {"testing/iotest", "\x03q\x03\x83\x01\x04"},
- {"testing/quick", "v\x01\x8f\x01\x05#\x10\x11"},
- {"testing/slogtest", "\rg\x03\x89\x01.\x05\x10\f"},
- {"testing/synctest", "\xe3\x01`\x12"},
- {"text/scanner", "\x03t\x83\x01,+\x02"},
- {"text/tabwriter", "w\x83\x01Y"},
- {"text/template", "t\x03C@\x01\n \x01\x05\x01\x02\x05\v\x02\x0e\x03\x02"},
- {"text/template/parse", "\x03t\xbc\x01\n\x01\x13\x02"},
- {"time", "t+\x1e$(*\r\x02\x13"},
- {"time/tzdata", "t\xce\x01\x13"},
+ {"sync", "\xda\x01\x02\x11\x01R\x0e\x14"},
+ {"sync/atomic", "\xe2\x02"},
+ {"syscall", "~'\x03\x01\x1d\n\x04\x06\r\x04U\b\x05\x01\x14"},
+ {"testing", "\x03\nq\x02\x01Y\x17\x14\f\x05\x1d\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\x0e\x02\x04"},
+ {"testing/cryptotest", "SV\\\x126\x03\x12"},
+ {"testing/fstest", "~\x03\x84\x01\x01\n(\x10\x03\t\b"},
+ {"testing/internal/testdeps", "\x02\v\xb7\x011\x10.\x03\x05\x03\x06\a\x02\x0f"},
+ {"testing/iotest", "\x03{\x03\x84\x01\x04"},
+ {"testing/quick", "\x80\x01\x01\x90\x01\x05%\x10\x11"},
+ {"testing/slogtest", "\rq\x03\x8a\x010\x05\x10\f"},
+ {"testing/synctest", "\xee\x01b\f\x06"},
+ {"text/scanner", "\x03~\x84\x01.+\x02"},
+ {"text/tabwriter", "\x81\x01\x84\x01["},
+ {"text/template", "~\x03BB\x01\n\"\x01\x05\x01\x02\x05\v\x02\x0e\x03\x02"},
+ {"text/template/parse", "\x03~\xbf\x01\n\x01\x13\x02"},
+ {"time", "~*D(,\r\x02\x13"},
+ {"time/tzdata", "~\xd1\x01\x13"},
{"unicode", ""},
{"unicode/utf16", ""},
{"unicode/utf8", ""},
- {"unique", "\x9b\x01!%\x01Q\r\x01\x14\x12"},
+ {"unique", "\xa4\x01\"&\x01S\r\x01\x14\x19"},
{"unsafe", ""},
- {"vendor/golang.org/x/crypto/chacha20", "\x10]\a\x95\x01*'"},
- {"vendor/golang.org/x/crypto/chacha20poly1305", "\x10\aV\a\xe2\x01\x04\x01\a"},
- {"vendor/golang.org/x/crypto/cryptobyte", "j\n\x03\x90\x01'!\n"},
+ {"uuid", "\x03\x01O\x1d\x03\v\xcf\x01\x0f"},
+ {"vendor/golang.org/x/crypto/chacha20", "\x10`\x0e\x96\x01,)"},
+ {"vendor/golang.org/x/crypto/chacha20poly1305", "\x10\aY\x0e\xe6\x01\x05\x01\f"},
+ {"vendor/golang.org/x/crypto/cryptobyte", "m\x11\x03\x91\x01)!\v"},
{"vendor/golang.org/x/crypto/cryptobyte/asn1", ""},
- {"vendor/golang.org/x/crypto/internal/alias", "\xd5\x02"},
- {"vendor/golang.org/x/crypto/internal/poly1305", "X\x15\x9c\x01"},
- {"vendor/golang.org/x/net/dns/dnsmessage", "t\xc7\x01"},
- {"vendor/golang.org/x/net/http/httpguts", "\x90\x02\x14\x1a\x15\r"},
- {"vendor/golang.org/x/net/http/httpproxy", "t\x03\x99\x01\x10\x05\x01\x18\x15\r"},
- {"vendor/golang.org/x/net/http2/hpack", "\x03q\x03\x83\x01F"},
- {"vendor/golang.org/x/net/idna", "w\x8f\x018\x15\x10\x02\x01"},
- {"vendor/golang.org/x/net/nettest", "\x03j\a\x03\x83\x01\x11\x05\x16\x01\f\n\x01\x02\x02\x01\f"},
- {"vendor/golang.org/x/sys/cpu", "\xa6\x02\r\n\x01\x17"},
- {"vendor/golang.org/x/text/secure/bidirule", "t\xdf\x01\x11\x01"},
- {"vendor/golang.org/x/text/transform", "\x03q\x86\x01Y"},
- {"vendor/golang.org/x/text/unicode/bidi", "\x03\bl\x87\x01>\x17"},
- {"vendor/golang.org/x/text/unicode/norm", "m\n\x83\x01F\x13\x11"},
- {"weak", "\x9b\x01\x98\x01\""},
+ {"vendor/golang.org/x/crypto/hkdf", "\x18\x01e\x15r"},
+ {"vendor/golang.org/x/crypto/internal/alias", "\xe2\x02"},
+ {"vendor/golang.org/x/crypto/internal/poly1305", "Z\x16\xa4\x01"},
+ {"vendor/golang.org/x/net/dns/dnsmessage", "~\xca\x01"},
+ {"vendor/golang.org/x/net/http/httpguts", "\x9b\x02\x16\x1a\x15\x10"},
+ {"vendor/golang.org/x/net/http/httpproxy", "~\x03\x9a\x01\x12\x05\x01\x18\x15\x10"},
+ {"vendor/golang.org/x/net/http2/hpack", "\x03{\x03\x84\x01H"},
+ {"vendor/golang.org/x/net/http3", "\x9c\x02@\x06\x0f\x04"},
+ {"vendor/golang.org/x/net/idna", "\x81\x01\x90\x01:\x13\x02\x17\x02\x01"},
+ {"vendor/golang.org/x/net/internal/http3", "\rN#\x03\x84\x01\v\x04\a\x01\x05\x10\x01\x16\x02\x01\x02\x0f\x10\x02\x04\x03"},
+ {"vendor/golang.org/x/net/internal/httpcommon", "\rq\x03\xa0\x01\x10\x01\x17\x01\x01\x02\x1f\x02"},
+ {"vendor/golang.org/x/net/internal/quic/quicwire", "p"},
+ {"vendor/golang.org/x/net/nettest", "\x03m\x0e\x03\x84\x01\x11\x05\x18\x01\f\n\x01\x02\x02\x01\f"},
+ {"vendor/golang.org/x/net/quic", "\x03\n\x01\x01\x01\t:\x04\x04\x15\x03\v\x03\x12r\x06\x06\x06\x04\x12\x06\x15\x02\x01\x02\x01\x01\r\x06\x02\x01\x01\x02\v"},
+ {"vendor/golang.org/x/sys/cpu", "\xb3\x02\r\n\x01\x17"},
+ {"vendor/golang.org/x/text/secure/bidirule", "~\xe2\x01\x18\x01"},
+ {"vendor/golang.org/x/text/transform", "\x03{\x87\x01["},
+ {"vendor/golang.org/x/text/unicode/bidi", "\x03\bv\x88\x01@\x17"},
+ {"vendor/golang.org/x/text/unicode/norm", "p\x11\x84\x01H\x13\x18"},
+ {"weak", "\xa4\x01\x9c\x01\""},
}
// bootstrap is the list of bootstrap packages extracted from cmd/dist.
@@ -408,6 +428,7 @@ var bootstrap = map[string]bool{
"cmd/compile/internal/logopt": true,
"cmd/compile/internal/loong64": true,
"cmd/compile/internal/loopvar": true,
+ "cmd/compile/internal/midway": true,
"cmd/compile/internal/mips": true,
"cmd/compile/internal/mips64": true,
"cmd/compile/internal/noder": true,
@@ -512,6 +533,7 @@ var bootstrap = map[string]bool{
"internal/race": true,
"internal/runtime/gc": true,
"internal/saferio": true,
+ "internal/strconv": true,
"internal/syscall/unix": true,
"internal/types/errors": true,
"internal/unsafeheader": true,
diff --git a/vendor/golang.org/x/tools/internal/stdlib/manifest.go b/vendor/golang.org/x/tools/internal/stdlib/manifest.go
index 33e4f505f3..2180c296ec 100644
--- a/vendor/golang.org/x/tools/internal/stdlib/manifest.go
+++ b/vendor/golang.org/x/tools/internal/stdlib/manifest.go
@@ -270,6 +270,7 @@ var PackageSymbols = map[string][]Symbol{
{"ContainsRune", Func, 7, "func(b []byte, r rune) bool"},
{"Count", Func, 0, "func(s []byte, sep []byte) int"},
{"Cut", Func, 18, "func(s []byte, sep []byte) (before []byte, after []byte, found bool)"},
+ {"CutLast", Func, 27, "func(s []byte, sep []byte) (before []byte, after []byte, found bool)"},
{"CutPrefix", Func, 20, "func(s []byte, prefix []byte) (after []byte, found bool)"},
{"CutSuffix", Func, 20, "func(s []byte, suffix []byte) (before []byte, found bool)"},
{"Equal", Func, 0, "func(a []byte, b []byte) bool"},
@@ -538,6 +539,7 @@ var PackageSymbols = map[string][]Symbol{
{"MD4", Const, 0, ""},
{"MD5", Const, 0, ""},
{"MD5SHA1", Const, 0, ""},
+ {"MLDSAMu", Const, 27, ""},
{"MessageSigner", Type, 25, ""},
{"PrivateKey", Type, 0, ""},
{"PublicKey", Type, 2, ""},
@@ -812,6 +814,40 @@ var PackageSymbols = map[string][]Symbol{
{"Size", Const, 0, ""},
{"Sum", Func, 2, "func(data []byte) [16]byte"},
},
+ "crypto/mldsa": {
+ {"(*Options).HashFunc", Method, 27, ""},
+ {"(*PrivateKey).Bytes", Method, 27, ""},
+ {"(*PrivateKey).Equal", Method, 27, ""},
+ {"(*PrivateKey).Public", Method, 27, ""},
+ {"(*PrivateKey).PublicKey", Method, 27, ""},
+ {"(*PrivateKey).Sign", Method, 27, ""},
+ {"(*PrivateKey).SignDeterministic", Method, 27, ""},
+ {"(*PublicKey).Bytes", Method, 27, ""},
+ {"(*PublicKey).Equal", Method, 27, ""},
+ {"(*PublicKey).Parameters", Method, 27, ""},
+ {"(Parameters).PublicKeySize", Method, 27, ""},
+ {"(Parameters).SignatureSize", Method, 27, ""},
+ {"(Parameters).String", Method, 27, ""},
+ {"GenerateKey", Func, 27, "func(params Parameters) (*PrivateKey, error)"},
+ {"MLDSA44", Func, 27, "func() Parameters"},
+ {"MLDSA44PublicKeySize", Const, 27, ""},
+ {"MLDSA44SignatureSize", Const, 27, ""},
+ {"MLDSA65", Func, 27, "func() Parameters"},
+ {"MLDSA65PublicKeySize", Const, 27, ""},
+ {"MLDSA65SignatureSize", Const, 27, ""},
+ {"MLDSA87", Func, 27, "func() Parameters"},
+ {"MLDSA87PublicKeySize", Const, 27, ""},
+ {"MLDSA87SignatureSize", Const, 27, ""},
+ {"NewPrivateKey", Func, 27, "func(params Parameters, seed []byte) (*PrivateKey, error)"},
+ {"NewPublicKey", Func, 27, "func(params Parameters, encoding []byte) (*PublicKey, error)"},
+ {"Options", Type, 27, ""},
+ {"Options.Context", Field, 27, ""},
+ {"Parameters", Type, 27, ""},
+ {"PrivateKey", Type, 27, ""},
+ {"PrivateKeySize", Const, 27, ""},
+ {"PublicKey", Type, 27, ""},
+ {"Verify", Func, 27, "func(pk *PublicKey, message []byte, signature []byte, opts *Options) error"},
+ },
"crypto/mlkem": {
{"(*DecapsulationKey1024).Bytes", Method, 24, ""},
{"(*DecapsulationKey1024).Decapsulate", Method, 24, ""},
@@ -1120,6 +1156,7 @@ var PackageSymbols = map[string][]Symbol{
{"ConnectionState.ECHAccepted", Field, 23, ""},
{"ConnectionState.HandshakeComplete", Field, 0, ""},
{"ConnectionState.HelloRetryRequest", Field, 26, ""},
+ {"ConnectionState.LocalCertificate", Field, 27, ""},
{"ConnectionState.NegotiatedProtocol", Field, 0, ""},
{"ConnectionState.NegotiatedProtocolIsMutual", Field, 0, ""},
{"ConnectionState.OCSPResponse", Field, 5, ""},
@@ -1152,6 +1189,10 @@ var PackageSymbols = map[string][]Symbol{
{"InsecureCipherSuites", Func, 14, "func() []*CipherSuite"},
{"Listen", Func, 0, "func(network string, laddr string, config *Config) (net.Listener, error)"},
{"LoadX509KeyPair", Func, 0, "func(certFile string, keyFile string) (Certificate, error)"},
+ {"MLDSA44", Const, 27, ""},
+ {"MLDSA65", Const, 27, ""},
+ {"MLDSA87", Const, 27, ""},
+ {"MLKEM1024", Const, 27, ""},
{"NewLRUClientSessionCache", Func, 3, "func(capacity int) ClientSessionCache"},
{"NewListener", Func, 0, "func(inner net.Listener, config *Config) net.Listener"},
{"NewResumptionState", Func, 21, "func(ticket []byte, state *SessionState) (*ClientSessionState, error)"},
@@ -1166,6 +1207,7 @@ var PackageSymbols = map[string][]Symbol{
{"ParseSessionState", Func, 21, "func(data []byte) (*SessionState, error)"},
{"QUICClient", Func, 21, "func(config *QUICConfig) *QUICConn"},
{"QUICConfig", Type, 21, ""},
+ {"QUICConfig.ClientHelloInfoConn", Field, 27, ""},
{"QUICConfig.EnableSessionEvents", Field, 23, ""},
{"QUICConfig.TLSConfig", Field, 21, ""},
{"QUICConn", Type, 21, ""},
@@ -1334,6 +1376,7 @@ var PackageSymbols = map[string][]Symbol{
{"Certificate.PublicKeyAlgorithm", Field, 0, ""},
{"Certificate.Raw", Field, 0, ""},
{"Certificate.RawIssuer", Field, 0, ""},
+ {"Certificate.RawSignatureAlgorithm", Field, 27, ""},
{"Certificate.RawSubject", Field, 0, ""},
{"Certificate.RawSubjectPublicKeyInfo", Field, 0, ""},
{"Certificate.RawTBSCertificate", Field, 0, ""},
@@ -1362,6 +1405,7 @@ var PackageSymbols = map[string][]Symbol{
{"CertificateRequest.PublicKey", Field, 3, ""},
{"CertificateRequest.PublicKeyAlgorithm", Field, 3, ""},
{"CertificateRequest.Raw", Field, 3, ""},
+ {"CertificateRequest.RawSignatureAlgorithm", Field, 27, ""},
{"CertificateRequest.RawSubject", Field, 3, ""},
{"CertificateRequest.RawSubjectPublicKeyInfo", Field, 3, ""},
{"CertificateRequest.RawTBSCertificateRequest", Field, 3, ""},
@@ -1422,6 +1466,10 @@ var PackageSymbols = map[string][]Symbol{
{"KeyUsageKeyEncipherment", Const, 0, ""},
{"MD2WithRSA", Const, 0, ""},
{"MD5WithRSA", Const, 0, ""},
+ {"MLDSA", Const, 27, ""},
+ {"MLDSA44", Const, 27, ""},
+ {"MLDSA65", Const, 27, ""},
+ {"MLDSA87", Const, 27, ""},
{"MarshalECPrivateKey", Func, 2, "func(key *ecdsa.PrivateKey) ([]byte, error)"},
{"MarshalPKCS1PrivateKey", Func, 0, "func(key *rsa.PrivateKey) []byte"},
{"MarshalPKCS1PublicKey", Func, 10, "func(key *rsa.PublicKey) []byte"},
@@ -1468,6 +1516,7 @@ var PackageSymbols = map[string][]Symbol{
{"RevocationList.Number", Field, 15, ""},
{"RevocationList.Raw", Field, 19, ""},
{"RevocationList.RawIssuer", Field, 19, ""},
+ {"RevocationList.RawSignatureAlgorithm", Field, 27, ""},
{"RevocationList.RawTBSRevocationList", Field, 19, ""},
{"RevocationList.RevokedCertificateEntries", Field, 21, ""},
{"RevocationList.RevokedCertificates", Field, 15, ""},
@@ -1648,6 +1697,7 @@ var PackageSymbols = map[string][]Symbol{
{"(Scanner).Scan", Method, 0, ""},
{"ColumnType", Type, 8, ""},
{"Conn", Type, 9, ""},
+ {"ConvertAssign", Func, 27, "func(scanCtx driver.ScanContext, dest any, src driver.Value) error"},
{"DB", Type, 0, ""},
{"DBStats", Type, 5, ""},
{"DBStats.Idle", Field, 11, ""},
@@ -1744,6 +1794,11 @@ var PackageSymbols = map[string][]Symbol{
{"(Rows).Next", Method, 0, ""},
{"(RowsAffected).LastInsertId", Method, 0, ""},
{"(RowsAffected).RowsAffected", Method, 0, ""},
+ {"(RowsColumnScanner).Close", Method, 27, ""},
+ {"(RowsColumnScanner).Columns", Method, 27, ""},
+ {"(RowsColumnScanner).Next", Method, 27, ""},
+ {"(RowsColumnScanner).NextRow", Method, 27, ""},
+ {"(RowsColumnScanner).ScanColumn", Method, 27, ""},
{"(RowsColumnTypeDatabaseTypeName).Close", Method, 8, ""},
{"(RowsColumnTypeDatabaseTypeName).ColumnTypeDatabaseTypeName", Method, 8, ""},
{"(RowsColumnTypeDatabaseTypeName).Columns", Method, 8, ""},
@@ -1815,12 +1870,14 @@ var PackageSymbols = map[string][]Symbol{
{"ResultNoRows", Var, 0, ""},
{"Rows", Type, 0, ""},
{"RowsAffected", Type, 0, ""},
+ {"RowsColumnScanner", Type, 27, ""},
{"RowsColumnTypeDatabaseTypeName", Type, 8, ""},
{"RowsColumnTypeLength", Type, 8, ""},
{"RowsColumnTypeNullable", Type, 8, ""},
{"RowsColumnTypePrecisionScale", Type, 8, ""},
{"RowsColumnTypeScanType", Type, 8, ""},
{"RowsNextResultSet", Type, 8, ""},
+ {"ScanContext", Type, 27, ""},
{"SessionResetter", Type, 10, ""},
{"Stmt", Type, 0, ""},
{"StmtExecContext", Type, 8, ""},
@@ -5038,24 +5095,32 @@ var PackageSymbols = map[string][]Symbol{
{"(*InvalidUnmarshalError).Error", Method, 0, ""},
{"(*MarshalerError).Error", Method, 0, ""},
{"(*MarshalerError).Unwrap", Method, 13, ""},
+ {"(*Number).UnmarshalJSONFrom", Method, 27, ""},
{"(*RawMessage).MarshalJSON", Method, 0, ""},
{"(*RawMessage).UnmarshalJSON", Method, 0, ""},
{"(*SyntaxError).Error", Method, 0, ""},
{"(*UnmarshalFieldError).Error", Method, 0, ""},
{"(*UnmarshalTypeError).Error", Method, 0, ""},
+ {"(*UnmarshalTypeError).Unwrap", Method, 27, ""},
{"(*UnsupportedTypeError).Error", Method, 0, ""},
{"(*UnsupportedValueError).Error", Method, 0, ""},
{"(Delim).String", Method, 5, ""},
{"(Marshaler).MarshalJSON", Method, 0, ""},
{"(Number).Float64", Method, 1, ""},
{"(Number).Int64", Method, 1, ""},
+ {"(Number).MarshalJSONTo", Method, 27, ""},
{"(Number).String", Method, 1, ""},
{"(RawMessage).MarshalJSON", Method, 8, ""},
{"(Unmarshaler).UnmarshalJSON", Method, 0, ""},
+ {"CallMethodsWithLegacySemantics", Func, 27, "func(v bool) Options"},
{"Compact", Func, 0, "func(dst *bytes.Buffer, src []byte) error"},
{"Decoder", Type, 0, ""},
+ {"DefaultOptionsV1", Func, 27, "func() Options"},
{"Delim", Type, 5, ""},
{"Encoder", Type, 0, ""},
+ {"FormatByteArrayAsArray", Func, 27, "func(v bool) Options"},
+ {"FormatBytesWithLegacySemantics", Func, 27, "func(v bool) Options"},
+ {"FormatDurationAsNano", Func, 27, "func(v bool) Options"},
{"HTMLEscape", Func, 0, "func(dst *bytes.Buffer, src []byte)"},
{"Indent", Func, 0, "func(dst *bytes.Buffer, src []byte, prefix string, indent string) error"},
{"InvalidUTF8Error", Type, 0, ""},
@@ -5068,19 +5133,29 @@ var PackageSymbols = map[string][]Symbol{
{"MarshalerError", Type, 0, ""},
{"MarshalerError.Err", Field, 0, ""},
{"MarshalerError.Type", Field, 0, ""},
+ {"MatchCaseSensitiveDelimiter", Func, 27, "func(v bool) Options"},
+ {"MergeWithLegacySemantics", Func, 27, "func(v bool) Options"},
{"NewDecoder", Func, 0, "func(r io.Reader) *Decoder"},
{"NewEncoder", Func, 0, "func(w io.Writer) *Encoder"},
{"Number", Type, 1, ""},
+ {"OmitEmptyWithLegacySemantics", Func, 27, "func(v bool) Options"},
+ {"Options", Type, 27, ""},
+ {"ParseBytesWithLooseRFC4648", Func, 27, "func(v bool) Options"},
+ {"ParseTimeWithLooseRFC3339", Func, 27, "func(v bool) Options"},
{"RawMessage", Type, 0, ""},
+ {"ReportErrorsWithLegacySemantics", Func, 27, "func(v bool) Options"},
+ {"StringifyWithLegacySemantics", Func, 27, "func(v bool) Options"},
{"SyntaxError", Type, 0, ""},
{"SyntaxError.Offset", Field, 0, ""},
{"Token", Type, 5, ""},
{"Unmarshal", Func, 0, "func(data []byte, v any) error"},
+ {"UnmarshalArrayFromAnyLength", Func, 27, "func(v bool) Options"},
{"UnmarshalFieldError", Type, 0, ""},
{"UnmarshalFieldError.Field", Field, 0, ""},
{"UnmarshalFieldError.Key", Field, 0, ""},
{"UnmarshalFieldError.Type", Field, 0, ""},
{"UnmarshalTypeError", Type, 0, ""},
+ {"UnmarshalTypeError.Err", Field, 27, ""},
{"UnmarshalTypeError.Field", Field, 8, ""},
{"UnmarshalTypeError.Offset", Field, 5, ""},
{"UnmarshalTypeError.Struct", Field, 8, ""},
@@ -5094,6 +5169,158 @@ var PackageSymbols = map[string][]Symbol{
{"UnsupportedValueError.Value", Field, 0, ""},
{"Valid", Func, 9, "func(data []byte) bool"},
},
+ "encoding/json/jsontext": {
+ {"(*Decoder).InputOffset", Method, 27, ""},
+ {"(*Decoder).Options", Method, 27, ""},
+ {"(*Decoder).PeekKind", Method, 27, ""},
+ {"(*Decoder).ReadToken", Method, 27, ""},
+ {"(*Decoder).ReadValue", Method, 27, ""},
+ {"(*Decoder).Reset", Method, 27, ""},
+ {"(*Decoder).SkipValue", Method, 27, ""},
+ {"(*Decoder).StackDepth", Method, 27, ""},
+ {"(*Decoder).StackIndex", Method, 27, ""},
+ {"(*Decoder).StackPointer", Method, 27, ""},
+ {"(*Decoder).UnreadBuffer", Method, 27, ""},
+ {"(*Encoder).AvailableBuffer", Method, 27, ""},
+ {"(*Encoder).Options", Method, 27, ""},
+ {"(*Encoder).OutputOffset", Method, 27, ""},
+ {"(*Encoder).Reset", Method, 27, ""},
+ {"(*Encoder).StackDepth", Method, 27, ""},
+ {"(*Encoder).StackIndex", Method, 27, ""},
+ {"(*Encoder).StackPointer", Method, 27, ""},
+ {"(*Encoder).WriteToken", Method, 27, ""},
+ {"(*Encoder).WriteValue", Method, 27, ""},
+ {"(*SyntacticError).Error", Method, 27, ""},
+ {"(*SyntacticError).Unwrap", Method, 27, ""},
+ {"(*Value).Canonicalize", Method, 27, ""},
+ {"(*Value).Compact", Method, 27, ""},
+ {"(*Value).Format", Method, 27, ""},
+ {"(*Value).Indent", Method, 27, ""},
+ {"(*Value).UnmarshalJSON", Method, 27, ""},
+ {"(Kind).String", Method, 27, ""},
+ {"(Pointer).AppendToken", Method, 27, ""},
+ {"(Pointer).Contains", Method, 27, ""},
+ {"(Pointer).IsValid", Method, 27, ""},
+ {"(Pointer).LastToken", Method, 27, ""},
+ {"(Pointer).Parent", Method, 27, ""},
+ {"(Pointer).Tokens", Method, 27, ""},
+ {"(Token).Bool", Method, 27, ""},
+ {"(Token).Clone", Method, 27, ""},
+ {"(Token).Float", Method, 27, ""},
+ {"(Token).Float32", Method, 27, ""},
+ {"(Token).Int", Method, 27, ""},
+ {"(Token).Kind", Method, 27, ""},
+ {"(Token).String", Method, 27, ""},
+ {"(Token).Uint", Method, 27, ""},
+ {"(Value).Clone", Method, 27, ""},
+ {"(Value).IsValid", Method, 27, ""},
+ {"(Value).Kind", Method, 27, ""},
+ {"(Value).MarshalJSON", Method, 27, ""},
+ {"(Value).String", Method, 27, ""},
+ {"AllowDuplicateNames", Func, 27, "func(v bool) Options"},
+ {"AllowInvalidUTF8", Func, 27, "func(v bool) Options"},
+ {"AppendFloat", Func, 27, "func(dst []byte, src float64, bits int) []byte"},
+ {"AppendFormat", Func, 27, "func[Bytes ~[]byte | ~string](dst []byte, src Bytes, opts ...Options) ([]byte, error)"},
+ {"AppendQuote", Func, 27, "func[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error)"},
+ {"AppendUnquote", Func, 27, "func[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error)"},
+ {"BeginArray", Var, 27, ""},
+ {"BeginObject", Var, 27, ""},
+ {"Bool", Func, 27, "func(b bool) Token"},
+ {"CanonicalizeRawFloats", Func, 27, "func(v bool) Options"},
+ {"CanonicalizeRawInts", Func, 27, "func(v bool) Options"},
+ {"Decoder", Type, 27, ""},
+ {"Encoder", Type, 27, ""},
+ {"EndArray", Var, 27, ""},
+ {"EndObject", Var, 27, ""},
+ {"ErrDuplicateName", Var, 27, ""},
+ {"ErrNonStringName", Var, 27, ""},
+ {"EscapeForHTML", Func, 27, "func(v bool) Options"},
+ {"EscapeForJS", Func, 27, "func(v bool) Options"},
+ {"False", Var, 27, ""},
+ {"Float", Func, 27, "func(n float64) Token"},
+ {"Float32", Func, 27, "func(n float32) Token"},
+ {"Int", Func, 27, "func(n int64) Token"},
+ {"Internal", Var, 27, ""},
+ {"Kind", Type, 27, ""},
+ {"KindBeginArray", Const, 27, ""},
+ {"KindBeginObject", Const, 27, ""},
+ {"KindEndArray", Const, 27, ""},
+ {"KindEndObject", Const, 27, ""},
+ {"KindFalse", Const, 27, ""},
+ {"KindInvalid", Const, 27, ""},
+ {"KindNull", Const, 27, ""},
+ {"KindNumber", Const, 27, ""},
+ {"KindString", Const, 27, ""},
+ {"KindTrue", Const, 27, ""},
+ {"Multiline", Func, 27, "func(v bool) Options"},
+ {"NewDecoder", Func, 27, "func(r io.Reader, opts ...Options) *Decoder"},
+ {"NewEncoder", Func, 27, "func(w io.Writer, opts ...Options) *Encoder"},
+ {"Null", Var, 27, ""},
+ {"Options", Type, 27, ""},
+ {"Pointer", Type, 27, ""},
+ {"PreserveRawStrings", Func, 27, "func(v bool) Options"},
+ {"ReorderRawObjects", Func, 27, "func(v bool) Options"},
+ {"SpaceAfterColon", Func, 27, "func(v bool) Options"},
+ {"SpaceAfterComma", Func, 27, "func(v bool) Options"},
+ {"String", Func, 27, "func(s string) Token"},
+ {"SyntacticError", Type, 27, ""},
+ {"SyntacticError.ByteOffset", Field, 27, ""},
+ {"SyntacticError.Err", Field, 27, ""},
+ {"SyntacticError.JSONPointer", Field, 27, ""},
+ {"Token", Type, 27, ""},
+ {"True", Var, 27, ""},
+ {"Uint", Func, 27, "func(n uint64) Token"},
+ {"Value", Type, 27, ""},
+ {"WithIndent", Func, 27, "func(indent string) Options"},
+ {"WithIndentPrefix", Func, 27, "func(prefix string) Options"},
+ },
+ "encoding/json/v2": {
+ {"(*SemanticError).Error", Method, 27, ""},
+ {"(*SemanticError).Unwrap", Method, 27, ""},
+ {"(Marshaler).MarshalJSON", Method, 27, ""},
+ {"(MarshalerTo).MarshalJSONTo", Method, 27, ""},
+ {"(Unmarshaler).UnmarshalJSON", Method, 27, ""},
+ {"(UnmarshalerFrom).UnmarshalJSONFrom", Method, 27, ""},
+ {"DefaultOptionsV2", Func, 27, "func() Options"},
+ {"Deterministic", Func, 27, "func(v bool) Options"},
+ {"ErrUnknownName", Var, 27, ""},
+ {"FormatNilMapAsNull", Func, 27, "func(v bool) Options"},
+ {"FormatNilSliceAsNull", Func, 27, "func(v bool) Options"},
+ {"GetOption", Func, 27, "func[T any](opts Options, setter func(T) Options) (T, bool)"},
+ {"JoinMarshalers", Func, 27, "func(ms ...*Marshalers) *Marshalers"},
+ {"JoinOptions", Func, 27, "func(srcs ...Options) Options"},
+ {"JoinUnmarshalers", Func, 27, "func(us ...*Unmarshalers) *Unmarshalers"},
+ {"Marshal", Func, 27, "func(in any, opts ...Options) (out []byte, err error)"},
+ {"MarshalEncode", Func, 27, "func(out *jsontext.Encoder, in any, opts ...Options) (err error)"},
+ {"MarshalFunc", Func, 27, "func[T any](fn func(T) ([]byte, error)) *Marshalers"},
+ {"MarshalToFunc", Func, 27, "func[T any](fn func(*jsontext.Encoder, T) error) *Marshalers"},
+ {"MarshalWrite", Func, 27, "func(out io.Writer, in any, opts ...Options) (err error)"},
+ {"Marshaler", Type, 27, ""},
+ {"MarshalerTo", Type, 27, ""},
+ {"Marshalers", Type, 27, ""},
+ {"MatchCaseInsensitiveNames", Func, 27, "func(v bool) Options"},
+ {"OmitZeroStructFields", Func, 27, "func(v bool) Options"},
+ {"Options", Type, 27, ""},
+ {"RejectUnknownMembers", Func, 27, "func(v bool) Options"},
+ {"SemanticError", Type, 27, ""},
+ {"SemanticError.ByteOffset", Field, 27, ""},
+ {"SemanticError.Err", Field, 27, ""},
+ {"SemanticError.GoType", Field, 27, ""},
+ {"SemanticError.JSONKind", Field, 27, ""},
+ {"SemanticError.JSONPointer", Field, 27, ""},
+ {"SemanticError.JSONValue", Field, 27, ""},
+ {"StringifyNumbers", Func, 27, "func(v bool) Options"},
+ {"Unmarshal", Func, 27, "func(in []byte, out any, opts ...Options) (err error)"},
+ {"UnmarshalDecode", Func, 27, "func(in *jsontext.Decoder, out any, opts ...Options) (err error)"},
+ {"UnmarshalFromFunc", Func, 27, "func[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers"},
+ {"UnmarshalFunc", Func, 27, "func[T any](fn func([]byte, T) error) *Unmarshalers"},
+ {"UnmarshalRead", Func, 27, "func(in io.Reader, out any, opts ...Options) (err error)"},
+ {"Unmarshaler", Type, 27, ""},
+ {"UnmarshalerFrom", Type, 27, ""},
+ {"Unmarshalers", Type, 27, ""},
+ {"WithMarshalers", Func, 27, "func(v *Marshalers) Options"},
+ {"WithUnmarshalers", Func, 27, "func(v *Unmarshalers) Options"},
+ },
"encoding/pem": {
{"Block", Type, 0, ""},
{"Block.Bytes", Field, 0, ""},
@@ -6002,6 +6229,7 @@ var PackageSymbols = map[string][]Symbol{
{"Shift", Func, 5, "func(x Value, op token.Token, s uint) Value"},
{"Sign", Func, 5, "func(x Value) int"},
{"String", Const, 5, ""},
+ {"StringLen", Func, 27, "func(x Value) int64"},
{"StringVal", Func, 5, "func(x Value) string"},
{"ToComplex", Func, 6, "func(x Value) Value"},
{"ToFloat", Func, 6, "func(x Value) Value"},
@@ -6183,6 +6411,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*ErrorList).Add", Method, 0, ""},
{"(*ErrorList).RemoveMultiples", Method, 0, ""},
{"(*ErrorList).Reset", Method, 0, ""},
+ {"(*Scanner).End", Method, 27, ""},
{"(*Scanner).Init", Method, 0, ""},
{"(*Scanner).Scan", Method, 0, ""},
{"(Error).Error", Method, 0, ""},
@@ -6222,6 +6451,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*File).SetLines", Method, 0, ""},
{"(*File).SetLinesForContent", Method, 0, ""},
{"(*File).Size", Method, 0, ""},
+ {"(*File).String", Method, 27, ""},
{"(*FileSet).AddExistingFiles", Method, 25, ""},
{"(*FileSet).AddFile", Method, 0, ""},
{"(*FileSet).Base", Method, 0, ""},
@@ -6529,6 +6759,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Tuple).Variables", Method, 24, ""},
{"(*TypeList).At", Method, 18, ""},
{"(*TypeList).Len", Method, 18, ""},
+ {"(*TypeList).String", Method, 27, ""},
{"(*TypeList).Types", Method, 24, ""},
{"(*TypeName).Exported", Method, 5, ""},
{"(*TypeName).Id", Method, 5, ""},
@@ -6547,6 +6778,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*TypeParam).Underlying", Method, 18, ""},
{"(*TypeParamList).At", Method, 18, ""},
{"(*TypeParamList).Len", Method, 18, ""},
+ {"(*TypeParamList).String", Method, 27, ""},
{"(*TypeParamList).TypeParams", Method, 24, ""},
{"(*Union).Len", Method, 18, ""},
{"(*Union).String", Method, 18, ""},
@@ -6571,9 +6803,14 @@ var PackageSymbols = map[string][]Symbol{
{"(Checker).PkgNameOf", Method, 22, ""},
{"(Checker).TypeOf", Method, 5, ""},
{"(Error).Error", Method, 5, ""},
+ {"(Hasher).Equal", Method, 27, ""},
+ {"(Hasher).Hash", Method, 27, ""},
+ {"(HasherIgnoreTags).Equal", Method, 27, ""},
+ {"(HasherIgnoreTags).Hash", Method, 27, ""},
{"(Importer).Import", Method, 5, ""},
{"(ImporterFrom).Import", Method, 6, ""},
{"(ImporterFrom).ImportFrom", Method, 6, ""},
+ {"(Instance).String", Method, 27, ""},
{"(Object).Exported", Method, 5, ""},
{"(Object).Id", Method, 5, ""},
{"(Object).Name", Method, 5, ""},
@@ -6643,6 +6880,8 @@ var PackageSymbols = map[string][]Symbol{
{"Float32", Const, 5, ""},
{"Float64", Const, 5, ""},
{"Func", Type, 5, ""},
+ {"Hasher", Type, 27, ""},
+ {"HasherIgnoreTags", Type, 27, ""},
{"Id", Func, 5, "func(pkg *Package, name string) string"},
{"Identical", Func, 5, "func(x Type, y Type) bool"},
{"IdenticalIgnoreTags", Func, 8, "func(x Type, y Type) bool"},
@@ -6877,9 +7116,13 @@ var PackageSymbols = map[string][]Symbol{
{"(*Hash).Write", Method, 14, ""},
{"(*Hash).WriteByte", Method, 14, ""},
{"(*Hash).WriteString", Method, 14, ""},
+ {"(ComparableHasher).Equal", Method, 27, ""},
+ {"(ComparableHasher).Hash", Method, 27, ""},
{"Bytes", Func, 19, "func(seed Seed, b []byte) uint64"},
{"Comparable", Func, 24, "func[T comparable](seed Seed, v T) uint64"},
+ {"ComparableHasher", Type, 27, ""},
{"Hash", Type, 14, ""},
+ {"Hasher", Type, 27, ""},
{"MakeSeed", Func, 14, "func() Seed"},
{"Seed", Type, 14, ""},
{"String", Func, 19, "func(seed Seed, s string) uint64"},
@@ -8035,6 +8278,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Int).CmpAbs", Method, 10, ""},
{"(*Int).Div", Method, 0, ""},
{"(*Int).DivMod", Method, 0, ""},
+ {"(*Int).Divide", Method, 27, ""},
{"(*Int).Exp", Method, 0, ""},
{"(*Int).FillBytes", Method, 15, ""},
{"(*Int).Float64", Method, 21, ""},
@@ -8119,9 +8363,11 @@ var PackageSymbols = map[string][]Symbol{
{"Accuracy", Type, 5, ""},
{"AwayFromZero", Const, 5, ""},
{"Below", Const, 5, ""},
+ {"Ceil", Const, 27, ""},
{"ErrNaN", Type, 5, ""},
{"Exact", Const, 5, ""},
{"Float", Type, 5, ""},
+ {"Floor", Const, 27, ""},
{"Int", Type, 0, ""},
{"Jacobi", Func, 5, "func(x *Int, y *Int) int"},
{"MaxBase", Const, 0, ""},
@@ -8133,12 +8379,14 @@ var PackageSymbols = map[string][]Symbol{
{"NewRat", Func, 0, "func(a int64, b int64) *Rat"},
{"ParseFloat", Func, 5, "func(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error)"},
{"Rat", Type, 0, ""},
+ {"Round", Const, 27, ""},
{"RoundingMode", Type, 5, ""},
{"ToNearestAway", Const, 5, ""},
{"ToNearestEven", Const, 5, ""},
{"ToNegativeInf", Const, 5, ""},
{"ToPositiveInf", Const, 5, ""},
{"ToZero", Const, 5, ""},
+ {"Trunc", Const, 27, ""},
{"Word", Type, 0, ""},
},
"math/bits": {
@@ -8290,6 +8538,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Rand).Int64", Method, 22, ""},
{"(*Rand).Int64N", Method, 22, ""},
{"(*Rand).IntN", Method, 22, ""},
+ {"(*Rand).N", Method, 27, ""},
{"(*Rand).NormFloat64", Method, 22, ""},
{"(*Rand).Perm", Method, 22, ""},
{"(*Rand).Shuffle", Method, 22, ""},
@@ -8985,7 +9234,7 @@ var PackageSymbols = map[string][]Symbol{
{"NoBody", Var, 8, ""},
{"NotFound", Func, 0, "func(w ResponseWriter, r *Request)"},
{"NotFoundHandler", Func, 0, "func() Handler"},
- {"ParseCookie", Func, 23, "func(line string) ([]*Cookie, error)"},
+ {"ParseCookie", Func, 23, "func(line string) (#rv1 []*Cookie, #rv2 error)"},
{"ParseHTTPVersion", Func, 0, "func(vers string) (major int, minor int, ok bool)"},
{"ParseSetCookie", Func, 23, "func(line string) (*Cookie, error)"},
{"ParseTime", Func, 1, "func(text string) (t time.Time, err error)"},
@@ -9061,6 +9310,7 @@ var PackageSymbols = map[string][]Symbol{
{"Server.BaseContext", Field, 13, ""},
{"Server.ConnContext", Field, 13, ""},
{"Server.ConnState", Field, 3, ""},
+ {"Server.DisableClientPriority", Field, 27, ""},
{"Server.DisableGeneralOptionsHandler", Field, 20, ""},
{"Server.ErrorLog", Field, 3, ""},
{"Server.HTTP2", Field, 24, ""},
@@ -9226,6 +9476,7 @@ var PackageSymbols = map[string][]Symbol{
{"NewRequestWithContext", Func, 23, "func(ctx context.Context, method string, target string, body io.Reader) *http.Request"},
{"NewServer", Func, 0, "func(handler http.Handler) *Server"},
{"NewTLSServer", Func, 0, "func(handler http.Handler) *Server"},
+ {"NewTestServer", Func, 27, "func(t testing.TB, handler http.Handler) *Server"},
{"NewUnstartedServer", Func, 0, "func(handler http.Handler) *Server"},
{"ResponseRecorder", Type, 0, ""},
{"ResponseRecorder.Body", Field, 0, ""},
@@ -9596,6 +9847,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Error).Timeout", Method, 6, ""},
{"(*Error).Unwrap", Method, 13, ""},
{"(*URL).AppendBinary", Method, 24, ""},
+ {"(*URL).Clone", Method, 27, ""},
{"(*URL).EscapedFragment", Method, 15, ""},
{"(*URL).EscapedPath", Method, 5, ""},
{"(*URL).Hostname", Method, 8, ""},
@@ -9616,6 +9868,7 @@ var PackageSymbols = map[string][]Symbol{
{"(EscapeError).Error", Method, 0, ""},
{"(InvalidHostError).Error", Method, 6, ""},
{"(Values).Add", Method, 0, ""},
+ {"(Values).Clone", Method, 27, ""},
{"(Values).Del", Method, 0, ""},
{"(Values).Encode", Method, 0, ""},
{"(Values).Get", Method, 0, ""},
@@ -10793,6 +11046,7 @@ var PackageSymbols = map[string][]Symbol{
{"ContainsRune", Func, 0, "func(s string, r rune) bool"},
{"Count", Func, 0, "func(s string, substr string) int"},
{"Cut", Func, 18, "func(s string, sep string) (before string, after string, found bool)"},
+ {"CutLast", Func, 27, "func(s string, sep string) (before string, after string, found bool)"},
{"CutPrefix", Func, 20, "func(s string, prefix string) (after string, found bool)"},
{"CutSuffix", Func, 20, "func(s string, suffix string) (before string, found bool)"},
{"EqualFold", Func, 0, "func(s string, t string) bool"},
@@ -17476,6 +17730,7 @@ var PackageSymbols = map[string][]Symbol{
{"TestHandler", Func, 21, "func(h slog.Handler, results func() []map[string]any) error"},
},
"testing/synctest": {
+ {"Sleep", Func, 27, "func(d time.Duration)"},
{"Test", Func, 25, "func(t *testing.T, f func(*testing.T))"},
{"Wait", Func, 25, "func()"},
},
@@ -17980,6 +18235,7 @@ var PackageSymbols = map[string][]Symbol{
{"Bassa_Vah", Var, 4, ""},
{"Batak", Var, 0, ""},
{"Bengali", Var, 0, ""},
+ {"Beria_Erfe", Var, 27, ""},
{"Bhaiksuki", Var, 7, ""},
{"Bidi_Control", Var, 0, ""},
{"Bopomofo", Var, 0, ""},
@@ -18029,6 +18285,7 @@ var PackageSymbols = map[string][]Symbol{
{"Extender", Var, 0, ""},
{"FoldCategory", Var, 0, ""},
{"FoldScript", Var, 0, ""},
+ {"Garay", Var, 27, ""},
{"Georgian", Var, 0, ""},
{"Glagolitic", Var, 0, ""},
{"Gothic", Var, 0, ""},
@@ -18038,6 +18295,7 @@ var PackageSymbols = map[string][]Symbol{
{"Gujarati", Var, 0, ""},
{"Gunjala_Gondi", Var, 13, ""},
{"Gurmukhi", Var, 0, ""},
+ {"Gurung_Khema", Var, 27, ""},
{"Han", Var, 0, ""},
{"Hangul", Var, 0, ""},
{"Hanifi_Rohingya", Var, 13, ""},
@@ -18049,6 +18307,9 @@ var PackageSymbols = map[string][]Symbol{
{"Hyphen", Var, 0, ""},
{"IDS_Binary_Operator", Var, 0, ""},
{"IDS_Trinary_Operator", Var, 0, ""},
+ {"IDS_Unary_Operator", Var, 27, ""},
+ {"ID_Compat_Math_Continue", Var, 27, ""},
+ {"ID_Compat_Math_Start", Var, 27, ""},
{"Ideographic", Var, 0, ""},
{"Imperial_Aramaic", Var, 0, ""},
{"In", Func, 2, "func(r rune, ranges ...*RangeTable) bool"},
@@ -18082,6 +18343,7 @@ var PackageSymbols = map[string][]Symbol{
{"Khmer", Var, 0, ""},
{"Khojki", Var, 4, ""},
{"Khudawadi", Var, 4, ""},
+ {"Kirat_Rai", Var, 27, ""},
{"L", Var, 0, ""},
{"LC", Var, 25, ""},
{"Lao", Var, 0, ""},
@@ -18125,6 +18387,7 @@ var PackageSymbols = map[string][]Symbol{
{"Miao", Var, 1, ""},
{"Mn", Var, 0, ""},
{"Modi", Var, 4, ""},
+ {"Modifier_Combining_Mark", Var, 27, ""},
{"Mongolian", Var, 0, ""},
{"Mro", Var, 4, ""},
{"Multani", Var, 5, ""},
@@ -18145,6 +18408,7 @@ var PackageSymbols = map[string][]Symbol{
{"Nyiakeng_Puachue_Hmong", Var, 14, ""},
{"Ogham", Var, 0, ""},
{"Ol_Chiki", Var, 0, ""},
+ {"Ol_Onal", Var, 27, ""},
{"Old_Hungarian", Var, 5, ""},
{"Old_Italic", Var, 0, ""},
{"Old_North_Arabian", Var, 4, ""},
@@ -18214,6 +18478,7 @@ var PackageSymbols = map[string][]Symbol{
{"Sharada", Var, 1, ""},
{"Shavian", Var, 0, ""},
{"Siddham", Var, 4, ""},
+ {"Sidetic", Var, 27, ""},
{"SignWriting", Var, 5, ""},
{"SimpleFold", Func, 0, "func(r rune) rune"},
{"Sinhala", Var, 0, ""},
@@ -18227,6 +18492,7 @@ var PackageSymbols = map[string][]Symbol{
{"Space", Var, 0, ""},
{"SpecialCase", Type, 0, ""},
{"Sundanese", Var, 0, ""},
+ {"Sunuwar", Var, 27, ""},
{"Syloti_Nagri", Var, 0, ""},
{"Symbol", Var, 0, ""},
{"Syriac", Var, 0, ""},
@@ -18235,6 +18501,7 @@ var PackageSymbols = map[string][]Symbol{
{"Tai_Le", Var, 0, ""},
{"Tai_Tham", Var, 0, ""},
{"Tai_Viet", Var, 0, ""},
+ {"Tai_Yo", Var, 27, ""},
{"Takri", Var, 1, ""},
{"Tamil", Var, 0, ""},
{"Tangsa", Var, 21, ""},
@@ -18252,7 +18519,10 @@ var PackageSymbols = map[string][]Symbol{
{"ToLower", Func, 0, "func(r rune) rune"},
{"ToTitle", Func, 0, "func(r rune) rune"},
{"ToUpper", Func, 0, "func(r rune) rune"},
+ {"Todhri", Var, 27, ""},
+ {"Tolong_Siki", Var, 27, ""},
{"Toto", Var, 21, ""},
+ {"Tulu_Tigalari", Var, 27, ""},
{"TurkishCase", Var, 0, ""},
{"Ugaritic", Var, 0, ""},
{"Unified_Ideograph", Var, 0, ""},
@@ -18320,6 +18590,21 @@ var PackageSymbols = map[string][]Symbol{
{"String", Func, 0, ""},
{"StringData", Func, 0, ""},
},
+ "uuid": {
+ {"(*UUID).UnmarshalText", Method, 27, ""},
+ {"(UUID).AppendText", Method, 27, ""},
+ {"(UUID).Compare", Method, 27, ""},
+ {"(UUID).MarshalText", Method, 27, ""},
+ {"(UUID).String", Method, 27, ""},
+ {"Max", Func, 27, "func() UUID"},
+ {"MustParse", Func, 27, "func(s string) UUID"},
+ {"New", Func, 27, "func() UUID"},
+ {"NewV4", Func, 27, "func() UUID"},
+ {"NewV7", Func, 27, "func() UUID"},
+ {"Nil", Func, 27, "func() UUID"},
+ {"Parse", Func, 27, "func(s string) (UUID, error)"},
+ {"UUID", Type, 27, ""},
+ },
"weak": {
{"(Pointer).Value", Method, 24, ""},
{"Make", Func, 24, "func[T any](ptr *T) Pointer[T]"},
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/element.go b/vendor/golang.org/x/tools/internal/typesinternal/element.go
index 5fe4d8abcb..89eeea1653 100644
--- a/vendor/golang.org/x/tools/internal/typesinternal/element.go
+++ b/vendor/golang.org/x/tools/internal/typesinternal/element.go
@@ -37,6 +37,10 @@ func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T type
tmset := msets.MethodSet(T)
for method := range tmset.Methods() {
sig := method.Type().(*types.Signature)
+ if sig.TypeParams() != nil {
+ continue // skip type-parameterized methods
+ }
+
// It is tempting to call visit(sig, false)
// but, as noted in golang.org/cl/65450043,
// the Signature.Recv field is ignored by
@@ -123,10 +127,10 @@ func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T type
case *types.TypeParam, *types.Union:
// forEachReachable must not be called on parameterized types.
- panic(T)
+ panic(fmt.Sprintf("ForEachElement called on type containing %T", T))
default:
- panic(T)
+ panic(fmt.Sprintf("ForEachElement called on unexpected type %T", T))
}
}
visit(T, false)
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types.go b/vendor/golang.org/x/tools/internal/typesinternal/types.go
index 6582cc81f5..d2c0b4c5ff 100644
--- a/vendor/golang.org/x/tools/internal/typesinternal/types.go
+++ b/vendor/golang.org/x/tools/internal/typesinternal/types.go
@@ -22,6 +22,7 @@ import (
"go/ast"
"go/token"
"go/types"
+ "iter"
"reflect"
"golang.org/x/tools/go/ast/inspector"
@@ -242,3 +243,30 @@ func ObjectKind(obj types.Object) string {
}
return "unknown symbol"
}
+
+// ImplicitFieldSelections returns the sequence of implicit embedded fields
+// traversed by the given selection. It skips the final leaf field or method.
+// The boolean component indicates whether the traversal traversed a pointer.
+func ImplicitFieldSelections(seln types.Selection) iter.Seq2[*types.Var, bool] {
+ return func(yield func(*types.Var, bool) bool) {
+ var (
+ t = seln.Recv()
+ indices = seln.Index()
+ )
+ for _, idx := range indices[:len(indices)-1] {
+ ptr, isPtr := t.Underlying().(*types.Pointer)
+ if isPtr {
+ t = ptr.Elem()
+ }
+ structType, ok := t.Underlying().(*types.Struct)
+ if !ok {
+ break
+ }
+ field := structType.Field(idx)
+ if !yield(field, isPtr) {
+ break
+ }
+ t = field.Type()
+ }
+ }
+}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go b/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
index d612a71029..706ad33ef8 100644
--- a/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
+++ b/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
@@ -259,13 +259,13 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
case *types.Signature:
var params []*ast.Field
for v := range t.Params().Variables() {
+ var names []*ast.Ident
+ if v.Name() != "" {
+ names = []*ast.Ident{ast.NewIdent(v.Name())}
+ }
params = append(params, &ast.Field{
- Type: TypeExpr(v.Type(), qual),
- Names: []*ast.Ident{
- {
- Name: v.Name(),
- },
- },
+ Type: TypeExpr(v.Type(), qual),
+ Names: names,
})
}
if t.Variadic() {
@@ -328,10 +328,10 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
return expr
case *types.Struct:
- return ast.NewIdent(t.String())
+ return ast.NewIdent(types.TypeString(t, qual))
case *types.Interface:
- return ast.NewIdent(t.String())
+ return ast.NewIdent(types.TypeString(t, qual))
case *types.Union:
if t.Len() == 0 {
diff --git a/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go b/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go
index 06a3f71063..f25a7bcc77 100644
--- a/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go
+++ b/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go
@@ -1,4 +1,4 @@
-// Copyright 2025 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -127,14 +127,13 @@ var file_google_rpc_status_proto_rawDesc = []byte{
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61,
0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52,
- 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x61, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e,
+ 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x5e, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x42, 0x0b, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3b, 0x73, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x33,
+ 0x75, 0x73, 0xa2, 0x02, 0x03, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go
index 326888ae35..7e3dbaad26 100644
--- a/vendor/google.golang.org/grpc/balancer/balancer.go
+++ b/vendor/google.golang.org/grpc/balancer/balancer.go
@@ -60,7 +60,7 @@ func Register(b Builder) {
if !envconfig.CaseSensitiveBalancerRegistries {
name = strings.ToLower(name)
if name != b.Name() {
- logger.Warningf("Balancer registered with name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", b.Name())
+ logger.Warningf("Balancer registered with name %q. grpc-go has switched to case sensitive balancer registries. GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES env variable will be removed in release v1.82.0", b.Name())
}
}
m[name] = b
@@ -85,7 +85,7 @@ func Get(name string) Builder {
if !envconfig.CaseSensitiveBalancerRegistries {
lowerName := strings.ToLower(name)
if lowerName != name {
- logger.Warningf("Balancer retrieved for name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", name)
+ logger.Warningf("Balancer retrieved for name %q. grpc-go has switched to case sensitive balancer registries. GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES env variable will be removed in release v1.82.0", name)
}
name = lowerName
}
diff --git a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go
index 518a69d573..d48bc304c2 100644
--- a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go
+++ b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go
@@ -35,9 +35,9 @@ import (
"google.golang.org/grpc/balancer"
"google.golang.org/grpc/balancer/pickfirst/internal"
"google.golang.org/grpc/connectivity"
+ "google.golang.org/grpc/experimental/balancer/weight"
expstats "google.golang.org/grpc/experimental/stats"
"google.golang.org/grpc/grpclog"
- "google.golang.org/grpc/internal/balancer/weight"
"google.golang.org/grpc/internal/envconfig"
internalgrpclog "google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/pretty"
diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go
index 5dec2dacc0..c4bca5203e 100644
--- a/vendor/google.golang.org/grpc/clientconn.go
+++ b/vendor/google.golang.org/grpc/clientconn.go
@@ -24,10 +24,12 @@ import (
"fmt"
"math"
"net/url"
+ "os"
"slices"
"strings"
"sync"
"sync/atomic"
+ "syscall"
"time"
"google.golang.org/grpc/balancer"
@@ -1268,8 +1270,9 @@ type addrConn struct {
channelz *channelz.SubChannel
- localityLabel string
- backendServiceLabel string
+ localityLabel string
+ backendServiceLabel string
+ disconnectErrorLabel string
}
// Note: this requires a lock on ac.mu.
@@ -1286,9 +1289,14 @@ func (ac *addrConn) updateConnectivityState(s connectivity.State, lastErr error)
// TODO: https://github.com/grpc/grpc-go/issues/7862 - Remove the second
// part of the if condition below once the issue is fixed.
if ac.state == connectivity.Ready || (ac.state == connectivity.Connecting && s == connectivity.Idle) {
- disconnectionsMetric.Record(ac.cc.metricsRecorderList, 1, ac.cc.target, ac.backendServiceLabel, ac.localityLabel, "unknown")
+ disconnectError := ac.disconnectErrorLabel
+ if disconnectError == "" {
+ disconnectError = "unknown"
+ }
+ disconnectionsMetric.Record(ac.cc.metricsRecorderList, 1, ac.cc.target, ac.backendServiceLabel, ac.localityLabel, disconnectError)
openConnectionsMetric.Record(ac.cc.metricsRecorderList, -1, ac.cc.target, ac.backendServiceLabel, ac.securityLevelLocked(), ac.localityLabel)
}
+ ac.disconnectErrorLabel = "" // Reset for next time
ac.state = s
ac.channelz.ChannelMetrics.State.Store(&s)
if lastErr == nil {
@@ -1483,11 +1491,11 @@ func (ac *addrConn) createTransport(ctx context.Context, addr resolver.Address,
addr.ServerName = ac.cc.getServerName(addr)
hctx, hcancel := context.WithCancel(ctx)
- onClose := func(r transport.GoAwayReason) {
+ onClose := func(info transport.GoAwayInfo) {
ac.mu.Lock()
defer ac.mu.Unlock()
// adjust params based on GoAwayReason
- ac.adjustParams(r)
+ ac.adjustParams(info.Reason)
if ctx.Err() != nil {
// Already shut down or connection attempt canceled. tearDown() or
// updateAddrs() already cleared the transport and canceled hctx
@@ -1504,6 +1512,7 @@ func (ac *addrConn) createTransport(ctx context.Context, addr resolver.Address,
return
}
ac.transport = nil
+ ac.disconnectErrorLabel = disconnectErrorString(info)
// Refresh the name resolver on any connection loss.
ac.cc.resolveNow(resolver.ResolveNowOptions{})
// Always go idle and wait for the LB policy to initiate a new
@@ -1560,6 +1569,32 @@ func (ac *addrConn) createTransport(ctx context.Context, addr resolver.Address,
return nil
}
+// disconnectErrorString returns the grpc.disconnect_error metric label corresponding
+// to the provided transport.GoAwayInfo, as specified by gRFC A94:
+// https://github.com/grpc/proposal/blob/master/A94-grpc-subchannel-disconnections-metrics.md
+func disconnectErrorString(info transport.GoAwayInfo) string {
+ err := info.Err
+ var sysErr syscall.Errno
+ switch {
+ case info.Reason != transport.GoAwayInvalid:
+ return fmt.Sprintf("GOAWAY %s", info.GoAwayCode.String())
+ case err == nil:
+ return "unknown"
+ case errors.Is(err, context.Canceled):
+ return "subchannel shutdown"
+ case errors.Is(err, syscall.ECONNRESET):
+ return "connection reset"
+ case errors.Is(err, syscall.ETIMEDOUT), errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded):
+ return "connection timed out"
+ case errors.Is(err, syscall.ECONNABORTED):
+ return "connection aborted"
+ case errors.As(err, &sysErr):
+ return "socket error"
+ default:
+ return "unknown"
+ }
+}
+
// startHealthCheck starts the health checking stream (RPC) to watch the health
// stats of this connection if health checking is requested and configured.
//
@@ -1663,6 +1698,9 @@ func (ac *addrConn) tearDown(err error) {
}
curTr := ac.transport
ac.transport = nil
+ if ac.disconnectErrorLabel == "" {
+ ac.disconnectErrorLabel = "subchannel shutdown"
+ }
// We have to set the state to Shutdown before anything else to prevent races
// between setting the state and logic that waits on context cancellation / etc.
ac.updateConnectivityState(connectivity.Shutdown, nil)
diff --git a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go
index cff016d66a..31344f175f 100644
--- a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go
+++ b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go
@@ -178,13 +178,8 @@ func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.
g.P("// This is a compile-time assertion to ensure that this generated file")
g.P("// is compatible with the grpc package it is being compiled against.")
- if *useGenericStreams {
- g.P("// Requires gRPC-Go v1.64.0 or later.")
- g.P("const _ = ", grpcPackage.Ident("SupportPackageIsVersion9"))
- } else {
- g.P("// Requires gRPC-Go v1.62.0 or later.")
- g.P("const _ = ", grpcPackage.Ident("SupportPackageIsVersion8")) // When changing, update version number above.
- }
+ g.P("// Requires gRPC-Go v1.64.0 or later.")
+ g.P("const _ = ", grpcPackage.Ident("SupportPackageIsVersion9"))
g.P()
for _, service := range file.Services {
genService(gen, file, g, service)
@@ -333,11 +328,7 @@ func clientSignature(g *protogen.GeneratedFile, method *protogen.Method) string
if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() {
s += "*" + g.QualifiedGoIdent(method.Output.GoIdent)
} else {
- if *useGenericStreams {
- s += clientStreamInterface(g, method)
- } else {
- s += method.Parent.GoName + "_" + method.GoName + "Client"
- }
+ s += clientStreamInterface(g, method)
}
s += ", error)"
return s
@@ -373,12 +364,8 @@ func genClientMethod(_ *protogen.Plugin, _ *protogen.File, g *protogen.Generated
return
}
- streamImpl := unexport(service.GoName) + method.GoName + "Client"
- if *useGenericStreams {
- typeParam := g.QualifiedGoIdent(method.Input.GoIdent) + ", " + g.QualifiedGoIdent(method.Output.GoIdent)
- streamImpl = g.QualifiedGoIdent(grpcPackage.Ident("GenericClientStream")) + "[" + typeParam + "]"
- }
-
+ typeParam := g.QualifiedGoIdent(method.Input.GoIdent) + ", " + g.QualifiedGoIdent(method.Output.GoIdent)
+ streamImpl := g.QualifiedGoIdent(grpcPackage.Ident("GenericClientStream")) + "[" + typeParam + "]"
serviceDescVar := service.GoName + "_ServiceDesc"
g.P("stream, err := c.cc.NewStream(ctx, &", serviceDescVar, ".Streams[", index, `], `, fmSymbol, `, cOpts...)`)
g.P("if err != nil { return nil, err }")
@@ -392,61 +379,9 @@ func genClientMethod(_ *protogen.Plugin, _ *protogen.File, g *protogen.Generated
g.P()
// Auxiliary types aliases, for backwards compatibility.
- if *useGenericStreams {
- g.P("// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.")
- g.P("type ", service.GoName, "_", method.GoName, "Client = ", clientStreamInterface(g, method))
- g.P()
- return
- }
-
- // Stream auxiliary types and methods, if we're not taking advantage of the
- // pre-implemented generic types and their methods.
- genSend := method.Desc.IsStreamingClient()
- genRecv := method.Desc.IsStreamingServer()
- genCloseAndRecv := !method.Desc.IsStreamingServer()
-
- g.P("type ", service.GoName, "_", method.GoName, "Client interface {")
- if genSend {
- g.P("Send(*", method.Input.GoIdent, ") error")
- }
- if genRecv {
- g.P("Recv() (*", method.Output.GoIdent, ", error)")
- }
- if genCloseAndRecv {
- g.P("CloseAndRecv() (*", method.Output.GoIdent, ", error)")
- }
- g.P(grpcPackage.Ident("ClientStream"))
- g.P("}")
- g.P()
-
- g.P("type ", streamImpl, " struct {")
- g.P(grpcPackage.Ident("ClientStream"))
- g.P("}")
+ g.P("// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.")
+ g.P("type ", service.GoName, "_", method.GoName, "Client = ", clientStreamInterface(g, method))
g.P()
-
- if genSend {
- g.P("func (x *", streamImpl, ") Send(m *", method.Input.GoIdent, ") error {")
- g.P("return x.ClientStream.SendMsg(m)")
- g.P("}")
- g.P()
- }
- if genRecv {
- g.P("func (x *", streamImpl, ") Recv() (*", method.Output.GoIdent, ", error) {")
- g.P("m := new(", method.Output.GoIdent, ")")
- g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }")
- g.P("return m, nil")
- g.P("}")
- g.P()
- }
- if genCloseAndRecv {
- g.P("func (x *", streamImpl, ") CloseAndRecv() (*", method.Output.GoIdent, ", error) {")
- g.P("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }")
- g.P("m := new(", method.Output.GoIdent, ")")
- g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }")
- g.P("return m, nil")
- g.P("}")
- g.P()
- }
}
func serverSignature(g *protogen.GeneratedFile, method *protogen.Method) string {
@@ -460,11 +395,7 @@ func serverSignature(g *protogen.GeneratedFile, method *protogen.Method) string
reqArgs = append(reqArgs, "*"+g.QualifiedGoIdent(method.Input.GoIdent))
}
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
- if *useGenericStreams {
- reqArgs = append(reqArgs, serverStreamInterface(g, method))
- } else {
- reqArgs = append(reqArgs, method.Parent.GoName+"_"+method.GoName+"Server")
- }
+ reqArgs = append(reqArgs, serverStreamInterface(g, method))
}
return method.GoName + "(" + strings.Join(reqArgs, ", ") + ") " + ret
}
@@ -545,11 +476,8 @@ func genServerMethod(_ *protogen.Plugin, _ *protogen.File, g *protogen.Generated
return hname
}
- streamImpl := unexport(service.GoName) + method.GoName + "Server"
- if *useGenericStreams {
- typeParam := g.QualifiedGoIdent(method.Input.GoIdent) + ", " + g.QualifiedGoIdent(method.Output.GoIdent)
- streamImpl = g.QualifiedGoIdent(grpcPackage.Ident("GenericServerStream")) + "[" + typeParam + "]"
- }
+ typeParam := g.QualifiedGoIdent(method.Input.GoIdent) + ", " + g.QualifiedGoIdent(method.Output.GoIdent)
+ streamImpl := g.QualifiedGoIdent(grpcPackage.Ident("GenericServerStream")) + "[" + typeParam + "]"
g.P("func ", hnameFuncNameFormatter(hname), "(srv interface{}, stream ", grpcPackage.Ident("ServerStream"), ") error {")
if !method.Desc.IsStreamingClient() {
@@ -563,59 +491,9 @@ func genServerMethod(_ *protogen.Plugin, _ *protogen.File, g *protogen.Generated
g.P()
// Auxiliary types aliases, for backwards compatibility.
- if *useGenericStreams {
- g.P("// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.")
- g.P("type ", service.GoName, "_", method.GoName, "Server = ", serverStreamInterface(g, method))
- g.P()
- return hname
- }
-
- // Stream auxiliary types and methods, if we're not taking advantage of the
- // pre-implemented generic types and their methods.
- genSend := method.Desc.IsStreamingServer()
- genSendAndClose := !method.Desc.IsStreamingServer()
- genRecv := method.Desc.IsStreamingClient()
-
- g.P("type ", service.GoName, "_", method.GoName, "Server interface {")
- if genSend {
- g.P("Send(*", method.Output.GoIdent, ") error")
- }
- if genSendAndClose {
- g.P("SendAndClose(*", method.Output.GoIdent, ") error")
- }
- if genRecv {
- g.P("Recv() (*", method.Input.GoIdent, ", error)")
- }
- g.P(grpcPackage.Ident("ServerStream"))
- g.P("}")
+ g.P("// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.")
+ g.P("type ", service.GoName, "_", method.GoName, "Server = ", serverStreamInterface(g, method))
g.P()
-
- g.P("type ", streamImpl, " struct {")
- g.P(grpcPackage.Ident("ServerStream"))
- g.P("}")
- g.P()
-
- if genSend {
- g.P("func (x *", streamImpl, ") Send(m *", method.Output.GoIdent, ") error {")
- g.P("return x.ServerStream.SendMsg(m)")
- g.P("}")
- g.P()
- }
- if genSendAndClose {
- g.P("func (x *", streamImpl, ") SendAndClose(m *", method.Output.GoIdent, ") error {")
- g.P("return x.ServerStream.SendMsg(m)")
- g.P("}")
- g.P()
- }
- if genRecv {
- g.P("func (x *", streamImpl, ") Recv() (*", method.Input.GoIdent, ", error) {")
- g.P("m := new(", method.Input.GoIdent, ")")
- g.P("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }")
- g.P("return m, nil")
- g.P("}")
- g.P()
- }
-
return hname
}
diff --git a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go
index 83bff58e0c..94e7ffcf58 100644
--- a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go
+++ b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go
@@ -42,10 +42,9 @@ import (
"google.golang.org/protobuf/types/pluginpb"
)
-const version = "1.6.1"
+const version = "1.6.2"
var requireUnimplemented *bool
-var useGenericStreams *bool
func main() {
showVersion := flag.Bool("version", false, "print the version and exit")
@@ -57,7 +56,6 @@ func main() {
var flags flag.FlagSet
requireUnimplemented = flags.Bool("require_unimplemented_servers", true, "set to false to match legacy behavior")
- useGenericStreams = flags.Bool("use_generic_streams_experimental", true, "set to true to use generic types for streaming client and server objects; this flag is EXPERIMENTAL and may be changed or removed in a future release")
protogen.Options{
ParamFunc: flags.Set,
diff --git a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/protoc-gen-go-grpc_test.sh b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/protoc-gen-go-grpc_test.sh
index c70fd0fa63..fb67b1f41b 100644
--- a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/protoc-gen-go-grpc_test.sh
+++ b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/protoc-gen-go-grpc_test.sh
@@ -30,7 +30,7 @@ popd
protoc \
--go-grpc_out="${TEMPDIR}" \
- --go-grpc_opt=paths=source_relative,use_generic_streams_experimental=true \
+ --go-grpc_opt=paths=source_relative \
"examples/route_guide/routeguide/route_guide.proto"
GOLDENFILE="examples/route_guide/routeguide/route_guide_grpc.pb.go"
diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go
index 4ec5f9cd09..3af08e1ab9 100644
--- a/vendor/google.golang.org/grpc/dialoptions.go
+++ b/vendor/google.golang.org/grpc/dialoptions.go
@@ -173,10 +173,8 @@ func newJoinDialOption(opts ...DialOption) DialOption {
// If this option is set to true every connection will release the buffer after
// flushing the data on the wire.
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a
-// later release.
+// Deprecated: shared write buffer is enabled by default. WithSharedWriteBuffer
+// will be removed in a future release.
func WithSharedWriteBuffer(val bool) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.SharedWriteBuffer = val
@@ -229,6 +227,14 @@ func WithInitialConnWindowSize(s int32) DialOption {
// WithStaticStreamWindowSize returns a DialOption which sets the initial
// stream window size to the value provided and disables dynamic flow control.
+//
+// Note that this also disables dynamic flow control for the connection,
+// falling back to a default static connection-level window of 64KB. To
+// use a larger connection-level window, you must also use the
+// [WithStaticConnWindowSize] DialOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func WithStaticStreamWindowSize(s int32) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.InitialWindowSize = s
@@ -239,6 +245,14 @@ func WithStaticStreamWindowSize(s int32) DialOption {
// WithStaticConnWindowSize returns a DialOption which sets the initial
// connection window size to the value provided and disables dynamic flow
// control.
+//
+// Note that this also disables dynamic flow control for individual streams,
+// falling back to a default static connection-level window of 64KB. To
+// explicitly configure the stream-level window size, you must also use the
+// [WithStaticStreamWindowSize] DialOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func WithStaticConnWindowSize(s int32) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.InitialConnWindowSize = s
diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go
index 296f38c3a8..bfa8b268fe 100644
--- a/vendor/google.golang.org/grpc/encoding/encoding.go
+++ b/vendor/google.golang.org/grpc/encoding/encoding.go
@@ -66,6 +66,9 @@ type Compressor interface {
// Decompress reads data from r, decompresses it, and provides the
// uncompressed data via the returned io.Reader. If an error occurs while
// initializing the decompressor, that error is returned instead.
+ //
+ // The returned io.Reader may optionally implement io.ReadCloser, and if it
+ // does, gRPC will call Close() exactly once.
Decompress(r io.Reader) (io.Reader, error)
// Name is the name of the compression codec and is used to set the content
// coding header. The result must be static; the result cannot change
diff --git a/vendor/google.golang.org/grpc/internal/balancer/weight/weight.go b/vendor/google.golang.org/grpc/experimental/balancer/weight/weight.go
similarity index 71%
rename from vendor/google.golang.org/grpc/internal/balancer/weight/weight.go
rename to vendor/google.golang.org/grpc/experimental/balancer/weight/weight.go
index 11beb07d14..beab9e07c9 100644
--- a/vendor/google.golang.org/grpc/internal/balancer/weight/weight.go
+++ b/vendor/google.golang.org/grpc/experimental/balancer/weight/weight.go
@@ -16,23 +16,23 @@
*
*/
-// Package weight contains utilities to manage endpoint weights. Weights are
-// used by LB policies such as ringhash to distribute load across multiple
-// endpoints.
+// Package weight contains utilities to manage endpoint weights.
+// Weights may be used by LB policies to distribute load across
+// multiple endpoints.
+//
+// # Experimental
+//
+// Notice: All APIs in this package are EXPERIMENTAL and may be changed
+// or removed in a later release.
package weight
-import (
- "fmt"
-
- "google.golang.org/grpc/resolver"
-)
+import "google.golang.org/grpc/resolver"
// attributeKey is the type used as the key to store EndpointInfo in the
// Attributes field of resolver.Endpoint.
type attributeKey struct{}
-// EndpointInfo will be stored in the Attributes field of Endpoints in order to
-// use the ringhash balancer.
+// EndpointInfo will be stored in the Attributes field of Endpoints.
type EndpointInfo struct {
Weight uint32
}
@@ -43,22 +43,16 @@ func (a EndpointInfo) Equal(o any) bool {
return ok && oa.Weight == a.Weight
}
-// Set returns a copy of endpoint in which the Attributes field is updated with
-// EndpointInfo.
+// Set returns a copy of endpoint in which the Attributes field is
+// updated with EndpointInfo.
func Set(endpoint resolver.Endpoint, epInfo EndpointInfo) resolver.Endpoint {
endpoint.Attributes = endpoint.Attributes.WithValue(attributeKey{}, epInfo)
return endpoint
}
-// String returns a human-readable representation of EndpointInfo.
-// This method is intended for logging, testing, and debugging purposes only.
-// Do not rely on the output format, as it is not guaranteed to remain stable.
-func (a EndpointInfo) String() string {
- return fmt.Sprintf("Weight: %d", a.Weight)
-}
-
-// FromEndpoint returns the EndpointInfo stored in the Attributes field of an
-// endpoint. It returns an empty EndpointInfo if attribute is not found.
+// FromEndpoint returns the EndpointInfo stored in the Attributes
+// field of an endpoint. It returns an empty EndpointInfo if attribute
+// is not found.
func FromEndpoint(endpoint resolver.Endpoint) EndpointInfo {
v := endpoint.Attributes.Value(attributeKey{})
ei, _ := v.(EndpointInfo)
diff --git a/vendor/google.golang.org/grpc/experimental/stats/metrics.go b/vendor/google.golang.org/grpc/experimental/stats/metrics.go
index 88742724a4..8732e53bde 100644
--- a/vendor/google.golang.org/grpc/experimental/stats/metrics.go
+++ b/vendor/google.golang.org/grpc/experimental/stats/metrics.go
@@ -20,10 +20,27 @@
package stats
import (
+ "context"
+
"google.golang.org/grpc/internal"
"google.golang.org/grpc/stats"
)
+type customLabelKey struct{}
+
+// NewContextWithCustomLabel returns a new context with the provided custom label
+// attached. The label will be propagated to all metric instruments specified in gRFC A108.
+func NewContextWithCustomLabel(ctx context.Context, label string) context.Context {
+ return context.WithValue(ctx, customLabelKey{}, label)
+}
+
+// CustomLabelFromContext returns the custom label from the context if it exists.
+// If the custom label is not present, it returns an empty string.
+func CustomLabelFromContext(ctx context.Context) string {
+ label, _ := ctx.Value(customLabelKey{}).(string)
+ return label
+}
+
// MetricsRecorder records on metrics derived from metric registry.
// Implementors must embed UnimplementedMetricsRecorder.
type MetricsRecorder interface {
diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
index 3ae45faa40..29d332e7b6 100644
--- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
+++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
@@ -59,6 +59,15 @@ var (
// unconditionally.
XDSEndpointHashKeyBackwardCompat = boolFromEnv("GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT", false)
+ // LabelServerGoroutines controls setting [runtime/pprof.Labels] on the
+ // goroutines spawned by [grpc.Server] type.
+ // For now, this is limited to the goroutines spawned to handle incoming
+ // requests on the server.
+ // Set "GRPC_GO_SERVER_GOROUTINE_LABELS" to "grpc.method=true" to
+ // enable this grpc.method label, or "all" to enable all valid labels.
+ // This variable is a bit-field.
+ LabelServerGoroutines = goroutineLabelsFromEnv("GRPC_GO_SERVER_GOROUTINE_LABELS", 0)
+
// RingHashSetRequestHashKey is set if the ring hash balancer can get the
// request hash header by setting the "requestHashHeader" field, according
// to gRFC A76. It can be disabled by setting the environment variable
@@ -78,12 +87,12 @@ var (
EnableDefaultPortForProxyTarget = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_DEFAULT_PORT_FOR_PROXY_TARGET", true)
// CaseSensitiveBalancerRegistries is set if the balancer registry should be
- // case-sensitive. This is disabled by default, but can be enabled by setting
+ // case-sensitive. This is enabled by default, but can be disabled by setting
// the env variable "GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES"
- // to "true".
+ // to "false".
//
- // TODO: After 2 releases, we will enable the env var by default.
- CaseSensitiveBalancerRegistries = boolFromEnv("GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES", false)
+ // This env varible will be removed in release v1.82.0.
+ CaseSensitiveBalancerRegistries = boolFromEnv("GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES", true)
// XDSAuthorityRewrite indicates whether xDS authority rewriting is enabled.
// This feature is defined in gRFC A81 and is enabled by setting the
@@ -104,28 +113,45 @@ var (
// to "false".
XDSRecoverPanicInResourceParsing = boolFromEnv("GRPC_GO_EXPERIMENTAL_XDS_RESOURCE_PANIC_RECOVERY", true)
- // DisableStrictPathChecking indicates whether strict path checking is
- // disabled. This feature can be disabled by setting the environment
- // variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to "true".
- //
- // When strict path checking is enabled, gRPC will reject requests with
- // paths that do not conform to the gRPC over HTTP/2 specification found at
- // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md.
- //
- // When disabled, gRPC will allow paths that do not contain a leading slash.
- // Enabling strict path checking is recommended for security reasons, as it
- // prevents potential path traversal vulnerabilities.
- //
- // A future release will remove this environment variable, enabling strict
- // path checking behavior unconditionally.
- DisableStrictPathChecking = boolFromEnv("GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING", false)
-
// EnablePriorityLBChildPolicyCache controls whether the priority balancer
// should cache child balancers that are removed from the LB policy config,
// for a period of 15 minutes. This is disabled by default, but can be
// enabled by setting the env variable
// GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE to true.
EnablePriorityLBChildPolicyCache = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE", false)
+
+ // Enable8KBDefaultHeaderListSize indicates that default maximum header list
+ // size is restricted to 8KB. This is disabled by default, but can be enabled
+ // by setting the environment variable
+ // "GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE" to "true".
+ // When disabled, the default maximum header list size of 16MB is used.
+ //
+ // When enabled, RPCs with a total size of headers exceeding 8KB will fail
+ // unless explicitly configured otherwise by the user.
+ //
+ // TODO: In release v1.82.0, env var will be enabled by default.
+ Enable8KBDefaultHeaderListSize = boolFromEnv("GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE", false)
+
+ // EnableHTTPFramerReadBufferPooling enables the use of the
+ // readyreader.Reader interface to perform non-memory-pinning reads,
+ // provided the underlying net.Conn supports it. This reduces memory usage
+ // when subchannels are idle.
+ //
+ // This environment variable serves as an escape hatch to disable the
+ // feature if unforeseen issues arise, and it will be removed in a future
+ // release.
+ EnableHTTPFramerReadBufferPooling = boolFromEnv("GRPC_GO_EXPERIMENTAL_HTTP_FRAMER_READ_BUFFER_POOLING", true)
+
+ // ControlBufferThrottleLimit is the maximum number of control frames that can
+ // be queued in the control buffer before throttling is applied. The value
+ // must be between 1 and 10,000, and is set to 100 by default.
+ //
+ // This environment variable serves as an escape hatch to increase the
+ // throttling limit if unforeseen issues arise, and it will be removed in a
+ // future release.
+ //
+ // TODO: Remove this env var once v1.83.0 is release.
+ ControlBufferThrottleLimit = uint64FromEnv("GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT", 100, 1, 10000)
)
func boolFromEnv(envVar string, def bool) bool {
@@ -150,3 +176,52 @@ func uint64FromEnv(envVar string, def, min, max uint64) uint64 {
}
return v
}
+
+// GoroutineLabels is a bitfield indicating which goroutine labels are enabled.
+type GoroutineLabels uint16
+
+func goroutineLabelsFromEnv(envVar string, def GoroutineLabels) GoroutineLabels {
+ val := def
+ v := os.Getenv(envVar)
+ if strings.EqualFold(v, "all") {
+ return AllGoroutineLabels
+ } else if strings.EqualFold(v, "none") {
+ return 0
+ }
+ for s := range strings.SplitSeq(v, ",") {
+ s = strings.TrimSpace(s)
+ if len(s) == 0 {
+ continue
+ }
+ pre, post, ok := strings.Cut(s, "=")
+ if !ok {
+ // no equals sign
+ continue
+ }
+ post = strings.TrimSpace(post)
+ pre = strings.TrimSpace(pre)
+ bitDesignator := GoroutineLabels(0)
+ switch {
+ case strings.EqualFold(pre, "grpc.method"):
+ bitDesignator = GoroutineLabelServerMethod
+ default:
+ continue
+ }
+ if strings.EqualFold(post, "true") {
+ val |= bitDesignator
+ } else if strings.EqualFold(post, "false") {
+ val &^= bitDesignator
+ }
+ }
+ return val
+}
+
+const (
+ // GoroutineLabelServerMethod sets the grpc.method label on new
+ // server-side gRPC streams.
+ GoroutineLabelServerMethod GoroutineLabels = 1 << iota
+)
+
+// AllGoroutineLabels is an or'd together bitfield of all valid GoroutineLabels
+// constant values (above).
+const AllGoroutineLabels = GoroutineLabelServerMethod
diff --git a/vendor/google.golang.org/grpc/internal/envconfig/xds.go b/vendor/google.golang.org/grpc/internal/envconfig/xds.go
index 7685d08b54..a2312f8eac 100644
--- a/vendor/google.golang.org/grpc/internal/envconfig/xds.go
+++ b/vendor/google.golang.org/grpc/internal/envconfig/xds.go
@@ -79,4 +79,24 @@ var (
// xDS bootstrap configuration via the `call_creds` field. For more details,
// see: https://github.com/grpc/proposal/blob/master/A97-xds-jwt-call-creds.md
XDSBootstrapCallCredsEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_BOOTSTRAP_CALL_CREDS", false)
+
+ // XDSSNIEnabled controls if gRPC should send SNI information in xDS
+ // configured TLS handshakes. For more details, see:
+ // https://github.com/grpc/proposal/blob/master/A101-SNI-setting-and-SNI-SAN-validation.md
+ XDSSNIEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_SNI", false)
+
+ // XDSORCAToLRSPropEnabled controls whether ORCA metrics are explicitly
+ // filtered and prefix-propagated to the LRS server. For more details, see:
+ // https://github.com/grpc/proposal/blob/master/A85-lrs-custom-metrics-changes.md
+ XDSORCAToLRSPropEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION", false)
+
+ // XDSClientExtProcEnabled indicates whether ExtProc filter is enabled on
+ // the client side. For more details, see:
+ // https://github.com/grpc/proposal/blob/master/A93-xds-ext-proc.md
+ XDSClientExtProcEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_EXT_PROC_ON_CLIENT", false)
+
+ // GCPAuthenticationFilterEnabled enables the xDS GCP Authentication
+ // filter. For more details, see:
+ // https://github.com/grpc/proposal/blob/master/A83-xds-gcp-authn-filter.md
+ GCPAuthenticationFilterEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_GCP_AUTHENTICATION_FILTER", false)
)
diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go b/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go
index b25b0baec3..1cc43fc6b8 100644
--- a/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go
+++ b/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go
@@ -39,7 +39,6 @@ func div(d, r time.Duration) int64 {
//
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests
func EncodeDuration(t time.Duration) string {
- // TODO: This is simplistic and not bandwidth efficient. Improve it.
if t <= 0 {
return "0n"
}
diff --git a/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go
index c2348a82ef..2d83b2eced 100644
--- a/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go
+++ b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go
@@ -73,7 +73,7 @@ type BinaryTieredBufferPool struct {
func NewBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) {
return newBinaryTiered(func(size int) bufferPool {
return newSizedBufferPool(size, true)
- }, &simpleBufferPool{shouldZero: true}, powerOfTwoExponents...)
+ }, &SimpleBufferPool{shouldZero: true}, powerOfTwoExponents...)
}
// NewDirtyBinaryTieredBufferPool returns a BufferPool backed by multiple
@@ -82,7 +82,7 @@ func NewBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (*BinaryTieredBuffe
func NewDirtyBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) {
return newBinaryTiered(func(size int) bufferPool {
return newSizedBufferPool(size, false)
- }, &simpleBufferPool{shouldZero: false}, powerOfTwoExponents...)
+ }, NewDirtySimplePool(), powerOfTwoExponents...)
}
func newBinaryTiered(sizedPoolFactory func(int) bufferPool, fallbackPool bufferPool, powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) {
@@ -258,7 +258,7 @@ func newSizedBufferPool(size int, zero bool) *sizedBufferPool {
// buffer pools for different sizes of buffers.
type TieredBufferPool struct {
sizedPools []*sizedBufferPool
- fallbackPool simpleBufferPool
+ fallbackPool SimpleBufferPool
}
// NewTieredBufferPool returns a BufferPool implementation that uses multiple
@@ -271,7 +271,7 @@ func NewTieredBufferPool(poolSizes ...int) *TieredBufferPool {
}
return &TieredBufferPool{
sizedPools: pools,
- fallbackPool: simpleBufferPool{shouldZero: true},
+ fallbackPool: SimpleBufferPool{shouldZero: true},
}
}
@@ -297,16 +297,26 @@ func (p *TieredBufferPool) getPool(size int) bufferPool {
return p.sizedPools[poolIdx]
}
-// simpleBufferPool is an implementation of the BufferPool interface that
+// SimpleBufferPool is an implementation of the mem.BufferPool interface that
// attempts to pool buffers with a sync.Pool. When Get is invoked, it tries to
// acquire a buffer from the pool but if that buffer is too small, it returns it
// to the pool and creates a new one.
-type simpleBufferPool struct {
+type SimpleBufferPool struct {
pool sync.Pool
shouldZero bool
}
-func (p *simpleBufferPool) Get(size int) *[]byte {
+// NewDirtySimplePool constructs a [SimpleBufferPool]. It does not initialize
+// the buffers before returning them. Callers must ensure they don't read the
+// buffers before writing data to them.
+func NewDirtySimplePool() *SimpleBufferPool {
+ return &SimpleBufferPool{
+ shouldZero: false,
+ }
+}
+
+// Get returns a buffer with specified length from the pool.
+func (p *SimpleBufferPool) Get(size int) *[]byte {
bs, ok := p.pool.Get().(*[]byte)
if ok && cap(*bs) >= size {
if p.shouldZero {
@@ -333,6 +343,7 @@ func (p *simpleBufferPool) Get(size int) *[]byte {
return &b
}
-func (p *simpleBufferPool) Put(buf *[]byte) {
+// Put returns a buffer to the pool.
+func (p *SimpleBufferPool) Put(buf *[]byte) {
p.pool.Put(buf)
}
diff --git a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
index f0603871c9..6320e9b576 100644
--- a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
+++ b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
@@ -106,15 +106,28 @@ type ClientStream interface {
// ClientInterceptor is an interceptor for gRPC client streams.
type ClientInterceptor interface {
- // NewStream produces a ClientStream for an RPC which may optionally use
- // the provided function to produce a stream for delegation. Note:
- // RPCInfo.Context should not be used (will be nil).
+ // NewStream creates a ClientStream for an RPC.
//
- // done is invoked when the RPC is finished using its connection, or could
- // not be assigned a connection. RPC operations may still occur on
- // ClientStream after done is called, since the interceptor is invoked by
- // application-layer operations. done must never be nil when called.
+ // Implementations must delegate stream creation to the provided newStream
+ // function. To intercept or override stream behavior, implementations
+ // may wrap the ClientStream returned by the delegate.
+ //
+ // Note: RPCInfo.Context is currently unused and will be nil.
+ //
+ // The done function is invoked when the RPC has finished using its
+ // underlying connection or if a connection could not be assigned. Because
+ // interceptors operate at the application layer, RPC operations may
+ // continue on the ClientStream even after done has been called. The
+ // caller must ensure done is non-nil.
+ //
+ // To ensure RPC completion notifications propagate through the entire
+ // interceptor chain, implementations must ensure that the done function
+ // passed to the delegate newStream invokes the done function passed to
+ // NewStream.
NewStream(ctx context.Context, ri RPCInfo, done func(), newStream func(ctx context.Context, done func()) (ClientStream, error)) (ClientStream, error)
+ // Close closes the interceptor. Once called, no new calls to NewStream are
+ // accepted. Ongoing calls to NewStream are allowed to complete.
+ Close()
}
// ServerInterceptor is an interceptor for incoming RPC's on gRPC server side.
@@ -123,6 +136,9 @@ type ServerInterceptor interface {
// information about connection RPC was received on, and HTTP Headers. This
// information will be piped into context.
AllowRPC(ctx context.Context) error // TODO: Make this a real interceptor for filters such as rate limiting.
+ // Close closes the interceptor. Once called, no new calls to NewStream are
+ // accepted. Ongoing calls to NewStream are allowed to complete.
+ Close()
}
type csKeyType string
diff --git a/vendor/google.golang.org/grpc/internal/stats/labels.go b/vendor/google.golang.org/grpc/internal/stats/labels.go
index fd33af51ae..5ea898cb53 100644
--- a/vendor/google.golang.org/grpc/internal/stats/labels.go
+++ b/vendor/google.golang.org/grpc/internal/stats/labels.go
@@ -19,24 +19,56 @@
// Package stats provides internal stats related functionality.
package stats
-import "context"
+import (
+ "context"
+ "maps"
+)
-// Labels are the labels for metrics.
-type Labels struct {
- // TelemetryLabels are the telemetry labels to record.
- TelemetryLabels map[string]string
+// LabelCallback is a function that is executed when telemetry
+// label keys are updated.
+type LabelCallback func(map[string]string)
+type telemetryLabelCallbackKey struct{}
+
+// UpdateLabels executes registered telemetry callbacks with the update labels. Labels
+// are copied before being processed by any callbacks to ensure mutations are not
+// shared among derived contexts.
+//
+// It is the responsibility of the registrant to handle conflicts or label resets.
+func UpdateLabels(ctx context.Context, update map[string]string) {
+ executeTelemetryLabelCallbacks(ctx, update)
}
-type labelsKey struct{}
+// RegisterTelemetryLabelCallback registers a callback function that is executed whenever
+// telemetry labels are updated.
+func RegisterTelemetryLabelCallback(ctx context.Context, callback LabelCallback) context.Context {
+ if callback == nil {
+ return ctx
+ }
+
+ callbacks, ok := ctx.Value(telemetryLabelCallbackKey{}).([]LabelCallback)
+ if !ok {
+ return context.WithValue(ctx, telemetryLabelCallbackKey{}, []LabelCallback{callback})
+ }
+ return context.WithValue(ctx, telemetryLabelCallbackKey{}, append(append([]LabelCallback(nil), callbacks...), callback))
-// GetLabels returns the Labels stored in the context, or nil if there is one.
-func GetLabels(ctx context.Context) *Labels {
- labels, _ := ctx.Value(labelsKey{}).(*Labels)
- return labels
}
-// SetLabels sets the Labels in the context.
-func SetLabels(ctx context.Context, labels *Labels) context.Context {
- // could also append
- return context.WithValue(ctx, labelsKey{}, labels)
+// executeTelemetryLabelCallback runs the registered callbacks in the order they were
+// registered on the context with the provided labels. If no callbacks are registered
+// it does nothing.
+//
+// To ensure callbacks do not mutate the state of the provided label map it is copied
+// before execution.
+func executeTelemetryLabelCallbacks(ctx context.Context, labels map[string]string) {
+ callbacks, ok := ctx.Value(telemetryLabelCallbackKey{}).([]LabelCallback)
+ if !ok {
+ return
+ }
+
+ labelsCopy := map[string]string{}
+ maps.Copy(labelsCopy, labels)
+ for _, callback := range callbacks {
+ callback(labelsCopy)
+ }
+
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/client_stream.go b/vendor/google.golang.org/grpc/internal/transport/client_stream.go
index cd8152ef13..ad382b0fda 100644
--- a/vendor/google.golang.org/grpc/internal/transport/client_stream.go
+++ b/vendor/google.golang.org/grpc/internal/transport/client_stream.go
@@ -19,6 +19,7 @@
package transport
import (
+ "fmt"
"sync/atomic"
"golang.org/x/net/http2"
@@ -28,6 +29,12 @@ import (
"google.golang.org/grpc/status"
)
+// nonGRPCDataMaxLen is the maximum length of nonGRPCDataBuf.
+//
+// NOTE: If changed this value, you MUST update the corresponding test in:
+// - /test/end2end_test.go:TestHTTPServerSendsNonGRPCHeaderSurfaceFurtherData
+const nonGRPCDataMaxLen = 1024
+
// ClientStream implements streaming functionality for a gRPC client.
type ClientStream struct {
Stream // Embed for common stream functionality.
@@ -46,7 +53,11 @@ type ClientStream struct {
// headerValid indicates whether a valid header was received. Only
// meaningful after headerChan is closed (always call waitOnHeader() before
// reading its value).
- headerValid bool
+ headerValid bool
+
+ nonGRPCStatus *status.Status // the initial status from the non-gRPC response header, finalized with collected data before closing.
+ nonGRPCDataBuf []byte // stores the data of a non-gRPC response.
+
noHeaders bool // set if the client never received headers (set only after the stream is done).
headerChanClosed uint32 // set when headerChan is closed. Used to avoid closing headerChan multiple times.
bytesReceived atomic.Bool // indicates whether any bytes have been received on this stream
@@ -54,6 +65,29 @@ type ClientStream struct {
statsHandler stats.Handler // nil for internal streams (e.g., health check, ORCA) where telemetry is not supported.
}
+func (s *ClientStream) startNonGRPCDataCollection(st *status.Status) {
+ s.nonGRPCStatus = st
+ s.nonGRPCDataBuf = make([]byte, 0, nonGRPCDataMaxLen)
+}
+
+// finalizeNonGRPCStatus builds the terminal status by appending the collected
+// response body to the original non-gRPC status message.
+func (s *ClientStream) finalizeNonGRPCStatus() *status.Status {
+ msg := fmt.Sprintf("%s\ndata: %q", s.nonGRPCStatus.Message(), s.nonGRPCDataBuf)
+ return status.New(s.nonGRPCStatus.Code(), msg)
+}
+
+// handleNonGRPCData collects non-gRPC body from the given data frame.
+// It returns non-nil value when the stream should be closed with it.
+func (s *ClientStream) handleNonGRPCData(f *parsedDataFrame) *status.Status {
+ n := min(f.data.Len(), nonGRPCDataMaxLen-len(s.nonGRPCDataBuf))
+ s.nonGRPCDataBuf = append(s.nonGRPCDataBuf, f.data.ReadOnlyData()[0:n]...)
+ if len(s.nonGRPCDataBuf) >= nonGRPCDataMaxLen || f.StreamEnded() {
+ return s.finalizeNonGRPCStatus()
+ }
+ return nil
+}
+
// Read reads an n byte message from the input stream.
func (s *ClientStream) Read(n int) (mem.BufferSlice, error) {
b, err := s.Stream.read(n)
diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
index 7efa524785..b9bae02498 100644
--- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
+++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
@@ -29,6 +29,7 @@ import (
"golang.org/x/net/http2"
"golang.org/x/net/http2/hpack"
+ "google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/mem"
)
@@ -96,61 +97,70 @@ func (il *itemList) isEmpty() bool {
return il.head == nil
}
-// The following defines various control items which could flow through
-// the control buffer of transport. They represent different aspects of
-// control tasks, e.g., flow control, settings, streaming resetting, etc.
-
-// maxQueuedTransportResponseFrames is the most queued "transport response"
-// frames we will buffer before preventing new reads from occurring on the
-// transport. These are control frames sent in response to client requests,
-// such as RST_STREAM due to bad headers or settings acks.
-const maxQueuedTransportResponseFrames = 50
+// maxQueuedControlBufferItems is the maximum number of frames (other than
+// HEADERS and DATA) that we will buffer before preventing new reads from
+// occurring on the transport. These are control frames sent in response to
+// client requests, or frames that result in work being scheduled, such as
+// RST_STREAM due to bad headers or settings acks.
+var maxQueuedControlBufferItems = int(envconfig.ControlBufferThrottleLimit)
type cbItem interface {
- isTransportResponseFrame() bool
+ isThrottled() bool
}
+// throttledItem represents every item in the controlBuffer to which the overall
+// throttling limit applies, other than outgoing HEADERS and DATA frames.
+type throttledItem struct{}
+
+func (throttledItem) isThrottled() bool { return true }
+
+// The following defines various control items which could flow through
+// the control buffer of transport. They represent different aspects of
+// control tasks, e.g., flow control, settings, streaming resetting, etc.
+
// registerStream is used to register an incoming stream with loopy writer.
type registerStream struct {
+ throttledItem
streamID uint32
wq *writeQuota
}
-func (*registerStream) isTransportResponseFrame() bool { return false }
-
-// headerFrame is also used to register stream on the client-side.
-type headerFrame struct {
+type clientHeaders struct {
streamID uint32
hf []hpack.HeaderField
- endStream bool // Valid on server side.
- initStream func(uint32) error // Used only on the client side.
+ initStream func(uint32) error
onWrite func()
- wq *writeQuota // write quota for the stream created.
- cleanup *cleanupStream // Valid on the server side.
- onOrphaned func(error) // Valid on client-side
+ wq *writeQuota
+ onOrphaned func(error)
}
-func (h *headerFrame) isTransportResponseFrame() bool {
- return h.cleanup != nil && h.cleanup.rst // Results in a RST_STREAM
+func (*clientHeaders) isThrottled() bool { return false }
+
+type serverHeaders struct {
+ streamID uint32
+ hf []hpack.HeaderField
+ endStream bool
+ onWrite func()
+ cleanup *cleanupStream
}
+func (h *serverHeaders) isThrottled() bool { return false }
+
type cleanupStream struct {
+ throttledItem
streamID uint32
rst bool
rstCode http2.ErrCode
onWrite func()
}
-func (c *cleanupStream) isTransportResponseFrame() bool { return c.rst } // Results in a RST_STREAM
-
type earlyAbortStream struct {
+ throttledItem
streamID uint32
rst bool
hf []hpack.HeaderField // Pre-built header fields
}
-func (*earlyAbortStream) isTransportResponseFrame() bool { return false }
-
type dataFrame struct {
streamID uint32
endStream bool
@@ -162,70 +172,60 @@ type dataFrame struct {
onEachWrite func()
}
-func (*dataFrame) isTransportResponseFrame() bool { return false }
+func (*dataFrame) isThrottled() bool { return false }
type incomingWindowUpdate struct {
+ throttledItem
streamID uint32
increment uint32
}
-func (*incomingWindowUpdate) isTransportResponseFrame() bool { return false }
-
type outgoingWindowUpdate struct {
+ throttledItem
streamID uint32
increment uint32
}
-func (*outgoingWindowUpdate) isTransportResponseFrame() bool {
- return false // window updates are throttled by thresholds
-}
-
type incomingSettings struct {
+ throttledItem
ss []http2.Setting
}
-func (*incomingSettings) isTransportResponseFrame() bool { return true } // Results in a settings ACK
-
type outgoingSettings struct {
+ throttledItem
ss []http2.Setting
}
-func (*outgoingSettings) isTransportResponseFrame() bool { return false }
-
type incomingGoAway struct {
+ throttledItem
}
-func (*incomingGoAway) isTransportResponseFrame() bool { return false }
-
type goAway struct {
+ throttledItem
code http2.ErrCode
debugData []byte
headsUp bool
closeConn error // if set, loopyWriter will exit with this error
}
-func (*goAway) isTransportResponseFrame() bool { return false }
-
type ping struct {
+ throttledItem
ack bool
data [8]byte
}
-func (*ping) isTransportResponseFrame() bool { return true }
-
type outFlowControlSizeRequest struct {
+ throttledItem
resp chan uint32
}
-func (*outFlowControlSizeRequest) isTransportResponseFrame() bool { return false }
-
// closeConnection is an instruction to tell the loopy writer to flush the
// framer and exit, which will cause the transport's connection to be closed
// (by the client or server). The transport itself will close after the reader
// encounters the EOF caused by the connection closure.
-type closeConnection struct{}
-
-func (closeConnection) isTransportResponseFrame() bool { return false }
+type closeConnection struct {
+ throttledItem
+}
type outStreamState int
@@ -379,9 +379,9 @@ func (c *controlBuffer) executeAndPut(f func() bool, it cbItem) (bool, error) {
c.consumerWaiting = false
}
c.list.enqueue(it)
- if it.isTransportResponseFrame() {
+ if it.isThrottled() {
c.transportResponseFrames++
- if c.transportResponseFrames == maxQueuedTransportResponseFrames {
+ if c.transportResponseFrames == maxQueuedControlBufferItems {
// We are adding the frame that puts us over the threshold; create
// a throttling channel.
ch := make(chan struct{})
@@ -436,8 +436,8 @@ func (c *controlBuffer) getOnceLocked() (any, error) {
return nil, nil
}
h := c.list.dequeue().(cbItem)
- if h.isTransportResponseFrame() {
- if c.transportResponseFrames == maxQueuedTransportResponseFrames {
+ if h.isThrottled() {
+ if c.transportResponseFrames == maxQueuedControlBufferItems {
// We are removing the frame that put us over the
// threshold; close and clear the throttling channel.
ch := c.trfChan.Swap(nil)
@@ -464,10 +464,8 @@ func (c *controlBuffer) finish() {
// is still not aware of these yet.
for head := c.list.dequeueAll(); head != nil; head = head.next {
switch v := head.it.(type) {
- case *headerFrame:
- if v.onOrphaned != nil { // It will be nil on the server-side.
- v.onOrphaned(ErrConnClosing)
- }
+ case *clientHeaders:
+ v.onOrphaned(ErrConnClosing)
case *dataFrame:
if !v.processing {
v.data.Free()
@@ -680,42 +678,38 @@ func (l *loopyWriter) registerStreamHandler(h *registerStream) {
l.estdStreams[h.streamID] = str
}
-func (l *loopyWriter) headerHandler(h *headerFrame) error {
- if l.side == serverSide {
- str, ok := l.estdStreams[h.streamID]
- if !ok {
- if l.logger.V(logLevel) {
- l.logger.Infof("Unrecognized streamID %d in loopyWriter", h.streamID)
- }
- return nil
- }
- // Case 1.A: Server is responding back with headers.
- if !h.endStream {
- return l.writeHeader(h.streamID, h.endStream, h.hf, h.onWrite)
+func (l *loopyWriter) serverHeaderHandler(hdr *serverHeaders) error {
+ str, ok := l.estdStreams[hdr.streamID]
+ if !ok {
+ if l.logger.V(logLevel) {
+ l.logger.Infof("Unrecognized streamID %d in loopyWriter", hdr.streamID)
}
- // else: Case 1.B: Server wants to close stream.
+ return nil
+ }
- if str.state != empty { // either active or waiting on stream quota.
- // add it str's list of items.
- str.itl.enqueue(h)
- return nil
- }
- if err := l.writeHeader(h.streamID, h.endStream, h.hf, h.onWrite); err != nil {
- return err
- }
- return l.cleanupStreamHandler(h.cleanup)
+ // Case 1: Server is responding back with headers.
+ if !hdr.endStream {
+ return l.writeHeader(hdr.streamID, hdr.endStream, hdr.hf, hdr.onWrite)
+ }
+
+ // Case 2: Server is closing the stream.
+ if str.state != empty { // either active or waiting on stream quota.
+ str.itl.enqueue(hdr)
+ return nil
+ }
+ if err := l.writeHeader(hdr.streamID, hdr.endStream, hdr.hf, hdr.onWrite); err != nil {
+ return err
}
- // Case 2: Client wants to originate stream.
+ return l.cleanupStreamHandler(hdr.cleanup)
+}
+
+func (l *loopyWriter) clientHeaderHandler(hdr *clientHeaders) error {
str := &outStream{
- id: h.streamID,
+ id: hdr.streamID,
state: empty,
itl: &itemList{},
- wq: h.wq,
+ wq: hdr.wq,
}
- return l.originateStream(str, h)
-}
-
-func (l *loopyWriter) originateStream(str *outStream, hdr *headerFrame) error {
// l.draining is set when handling GoAway. In which case, we want to avoid
// creating new streams.
if l.draining {
@@ -726,7 +720,7 @@ func (l *loopyWriter) originateStream(str *outStream, hdr *headerFrame) error {
if err := hdr.initStream(str.id); err != nil {
return err
}
- if err := l.writeHeader(str.id, hdr.endStream, hdr.hf, hdr.onWrite); err != nil {
+ if err := l.writeHeader(str.id, false, hdr.hf, hdr.onWrite); err != nil {
return err
}
l.estdStreams[str.id] = str
@@ -882,8 +876,10 @@ func (l *loopyWriter) handle(i any) error {
return l.incomingSettingsHandler(i)
case *outgoingSettings:
return l.outgoingSettingsHandler(i)
- case *headerFrame:
- return l.headerHandler(i)
+ case *clientHeaders:
+ return l.clientHeaderHandler(i)
+ case *serverHeaders:
+ return l.serverHeaderHandler(i)
case *registerStream:
l.registerStreamHandler(i)
case *cleanupStream:
@@ -956,39 +952,16 @@ func (l *loopyWriter) processData() (bool, error) {
// from data is copied to h to make as big as the maximum possible HTTP2 frame
// size.
- if len(dataItem.h) == 0 && reader.Remaining() == 0 { // Empty data frame
- // Client sends out empty data frame with endStream = true
- if err := l.framer.writeData(dataItem.streamID, dataItem.endStream, nil); err != nil {
- return false, err
- }
- str.itl.dequeue() // remove the empty data item from stream
- reader.Close()
- if str.itl.isEmpty() {
- str.state = empty
- } else if trailer, ok := str.itl.peek().(*headerFrame); ok { // the next item is trailers.
- if err := l.writeHeader(trailer.streamID, trailer.endStream, trailer.hf, trailer.onWrite); err != nil {
- return false, err
- }
- if err := l.cleanupStreamHandler(trailer.cleanup); err != nil {
- return false, err
- }
- } else {
- l.activeStreams.enqueue(str)
- }
- return false, nil
- }
-
+ isEmpty := len(dataItem.h) == 0 && reader.Remaining() == 0
// Figure out the maximum size we can send
maxSize := http2MaxFrameLen
- if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota <= 0 { // stream-level flow control.
+ strQuota := int(l.oiws) - str.bytesOutStanding
+ if strQuota <= 0 && !isEmpty { // stream-level flow control.
str.state = waitingOnStreamQuota
return false, nil
- } else if maxSize > strQuota {
- maxSize = strQuota
- }
- if maxSize > int(l.sendQuota) { // connection-level flow control.
- maxSize = int(l.sendQuota)
}
+ maxSize = min(maxSize, max(strQuota, 0))
+ maxSize = min(maxSize, int(l.sendQuota)) // connection-level flow control.
// Compute how much of the header and data we can send within quota and max frame length
hSize := min(maxSize, len(dataItem.h))
dSize := min(maxSize-hSize, reader.Remaining())
@@ -1039,19 +1012,23 @@ func (l *loopyWriter) processData() (bool, error) {
reader.Close()
str.itl.dequeue()
}
+ return false, l.updateStreamAfterWrite(str)
+}
+
+func (l *loopyWriter) updateStreamAfterWrite(str *outStream) error {
if str.itl.isEmpty() {
str.state = empty
- } else if trailer, ok := str.itl.peek().(*headerFrame); ok { // The next item is trailers.
+ } else if trailer, ok := str.itl.peek().(*serverHeaders); ok { // the next item is trailers.
if err := l.writeHeader(trailer.streamID, trailer.endStream, trailer.hf, trailer.onWrite); err != nil {
- return false, err
+ return err
}
if err := l.cleanupStreamHandler(trailer.cleanup); err != nil {
- return false, err
+ return err
}
} else if int(l.oiws)-str.bytesOutStanding <= 0 { // Ran out of stream quota.
str.state = waitingOnStreamQuota
} else { // Otherwise add it back to the list of active streams.
l.activeStreams.enqueue(str)
}
- return false, nil
+ return nil
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go
index 7cfbc9637b..98cef9ec2b 100644
--- a/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go
+++ b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go
@@ -115,7 +115,6 @@ func (f *trInFlow) getSize() uint32 {
return atomic.LoadUint32(&f.effectiveWindowSize)
}
-// TODO(mmukhi): Simplify this code.
// inFlow deals with inbound flow control
type inFlow struct {
mu sync.Mutex
@@ -174,14 +173,14 @@ func (f *inFlow) maybeAdjust(n uint32) uint32 {
// onData is invoked when some data frame is received. It updates pendingData.
func (f *inFlow) onData(n uint32) error {
f.mu.Lock()
+ defer f.mu.Unlock()
+
f.pendingData += n
if f.pendingData+f.pendingUpdate > f.limit+f.delta {
limit := f.limit
rcvd := f.pendingData + f.pendingUpdate
- f.mu.Unlock()
return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", rcvd, limit)
}
- f.mu.Unlock()
return nil
}
@@ -189,8 +188,9 @@ func (f *inFlow) onData(n uint32) error {
// to be sent to the peer.
func (f *inFlow) onRead(n uint32) uint32 {
f.mu.Lock()
+ defer f.mu.Unlock()
+
if f.pendingData == 0 {
- f.mu.Unlock()
return 0
}
f.pendingData -= n
@@ -205,9 +205,7 @@ func (f *inFlow) onRead(n uint32) uint32 {
if f.pendingUpdate >= f.limit/4 {
wu := f.pendingUpdate
f.pendingUpdate = 0
- f.mu.Unlock()
return wu
}
- f.mu.Unlock()
return 0
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
index 7ab3422b8a..a8356c9adb 100644
--- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
@@ -479,8 +479,8 @@ func (ht *serverHandlerTransport) runStream() {
func (ht *serverHandlerTransport) incrMsgRecv() {}
-func (ht *serverHandlerTransport) Drain(string) {
- panic("Drain() is not implemented")
+func (ht *serverHandlerTransport) Drain(s string) {
+ ht.Close(errors.New(s))
}
// mapRecvMsgError returns the non-nil err into the appropriate
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
index c943503f35..822c09ba62 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
@@ -39,6 +39,7 @@ import (
"google.golang.org/grpc/internal"
"google.golang.org/grpc/internal/channelz"
icredentials "google.golang.org/grpc/internal/credentials"
+ "google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/grpcsync"
"google.golang.org/grpc/internal/grpcutil"
@@ -134,6 +135,8 @@ type http2Client struct {
// goAwayDebugMessage contains a detailed human readable string about a
// GoAway frame, useful for error messages.
goAwayDebugMessage string
+ // goAwayCode records the http2.ErrCode received with the GoAway frame.
+ goAwayCode http2.ErrCode
// A condition variable used to signal when the keepalive goroutine should
// go dormant. The condition for dormancy is based on the number of active
// streams and the `PermitWithoutStream` keepalive client parameter. And
@@ -147,7 +150,7 @@ type http2Client struct {
channelz *channelz.Socket
- onClose func(GoAwayReason)
+ onClose OnCloseFunc
bufferPool mem.BufferPool
@@ -204,7 +207,7 @@ func isTemporary(err error) bool {
// NewHTTP2Client constructs a connected ClientTransport to addr based on HTTP2
// and starts to receive messages on it. Non-nil error returns if construction
// fails.
-func NewHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onClose func(GoAwayReason)) (_ ClientTransport, err error) {
+func NewHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onClose OnCloseFunc) (_ ClientTransport, err error) {
scheme := "http"
ctx, cancel := context.WithCancel(ctx)
defer func() {
@@ -316,7 +319,13 @@ func NewHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
}
writeBufSize := opts.WriteBufferSize
readBufSize := opts.ReadBufferSize
+ // The default header list size is moving from 16MB to 8KB. The 8KB limit
+ // is only used if Enable8KBDefaultHeaderListSize is true; otherwise, the
+ // old 16MB default is used. User-specified options always take precedence.
maxHeaderListSize := defaultClientMaxHeaderListSize
+ if envconfig.Enable8KBDefaultHeaderListSize {
+ maxHeaderListSize = upcomingDefaultHeaderListSize
+ }
if opts.MaxHeaderListSize != nil {
maxHeaderListSize = *opts.MaxHeaderListSize
}
@@ -797,9 +806,8 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr, handler s
close(s.headerChan)
}
}
- hdr := &headerFrame{
- hf: headerFields,
- endStream: false,
+ hdr := &clientHeaders{
+ hf: headerFields,
initStream: func(uint32) error {
t.mu.Lock()
// TODO: handle transport closure in loopy instead and remove this
@@ -877,8 +885,8 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr, handler s
return false
}
}
- if sz > int64(upcomingDefaultHeaderListSize) {
- t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize)
+ if !envconfig.Enable8KBDefaultHeaderListSize && sz > int64(upcomingDefaultHeaderListSize) {
+ t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In release v1.82.0, GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE will be enabled by default, enforcing this limit.", sz, upcomingDefaultHeaderListSize)
}
return true
}
@@ -1015,7 +1023,7 @@ func (t *http2Client) Close(err error) {
// Call t.onClose ASAP to prevent the client from attempting to create new
// streams.
if t.state != draining {
- t.onClose(GoAwayInvalid)
+ t.onClose(GoAwayInfo{Reason: GoAwayInvalid, GoAwayCode: http2.ErrCodeNo, Err: err})
}
t.state = closing
streams := t.activeStreams
@@ -1086,7 +1094,7 @@ func (t *http2Client) GracefulClose() {
if t.logger.V(logLevel) {
t.logger.Infof("GracefulClose called")
}
- t.onClose(GoAwayInvalid)
+ t.onClose(GoAwayInfo{Reason: GoAwayInvalid, GoAwayCode: http2.ErrCodeNo})
t.state = draining
active := len(t.activeStreams)
t.mu.Unlock()
@@ -1222,10 +1230,30 @@ func (t *http2Client) handleData(f *parsedDataFrame) {
t.closeStream(s, io.EOF, true, http2.ErrCodeFlowControl, status.New(codes.Internal, err.Error()), nil, false)
return
}
+
+ if s.nonGRPCStatus != nil {
+ // The frame should be handled as a non-gRPC response body
+ st := s.handleNonGRPCData(f)
+ if st != nil {
+ t.closeStream(s, st.Err(), true, http2.ErrCodeProtocol, st, nil, true)
+ return
+ }
+ if w := s.fc.onRead(size); w > 0 {
+ t.controlBuf.put(&outgoingWindowUpdate{
+ streamID: s.id,
+ increment: w,
+ })
+ }
+ return
+ }
+
dataLen := f.data.Len()
if f.Header().Flags.Has(http2.FlagDataPadded) {
if w := s.fc.onRead(size - uint32(dataLen)); w > 0 {
- t.controlBuf.put(&outgoingWindowUpdate{s.id, w})
+ t.controlBuf.put(&outgoingWindowUpdate{
+ streamID: s.id,
+ increment: w,
+ })
}
}
if dataLen > 0 {
@@ -1236,7 +1264,10 @@ func (t *http2Client) handleData(f *parsedDataFrame) {
// The server has closed the stream without sending trailers. Record that
// the read direction is closed, and set the status appropriately.
if f.StreamEnded() {
- t.closeStream(s, io.EOF, false, http2.ErrCodeNo, status.New(codes.Internal, "server closed the stream without sending trailers"), nil, true)
+ // If client received END_STREAM from server while stream was still
+ // active, send RST_STREAM.
+ rstStream := s.getState() == streamActive
+ t.closeStream(s, io.EOF, rstStream, http2.ErrCodeNo, status.New(codes.Internal, "server closed the stream without sending trailers"), nil, true)
}
}
@@ -1372,7 +1403,7 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) error {
// draining, to allow the client to stop attempting to create streams
// before disallowing new streams on this connection.
if t.state != draining {
- t.onClose(t.goAwayReason)
+ t.onClose(GoAwayInfo{Reason: t.goAwayReason, GoAwayCode: t.goAwayCode})
t.state = draining
}
}
@@ -1422,6 +1453,7 @@ func (t *http2Client) setGoAwayReason(f *http2.GoAwayFrame) {
} else {
t.goAwayDebugMessage = fmt.Sprintf("code: %s, debug data: %q", f.ErrCode, string(f.DebugData()))
}
+ t.goAwayCode = f.ErrCode
}
func (t *http2Client) GetGoAwayReason() (GoAwayReason, string) {
@@ -1462,6 +1494,17 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
return
}
+ // If we are collecting non-gRPC response data and receive a trailing
+ // HEADERS frame with END_STREAM, finalize the buffered data and close
+ // the stream.
+ if s.nonGRPCStatus != nil {
+ if endStream {
+ st := s.finalizeNonGRPCStatus()
+ t.closeStream(s, st.Err(), true, http2.ErrCodeProtocol, st, nil, true)
+ }
+ return
+ }
+
var (
// If a gRPC Response-Headers has already been received, then it means
// that the peer is speaking gRPC and we are in gRPC mode.
@@ -1562,7 +1605,12 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
}
se := status.New(grpcErrorCode, strings.Join(errs, "; "))
- t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
+ if endStream {
+ t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, true)
+ return
+ }
+
+ s.startNonGRPCDataCollection(se)
return
}
@@ -1833,7 +1881,7 @@ func (t *http2Client) getOutFlowWindow() int64 {
resp := make(chan uint32, 1)
timer := time.NewTimer(time.Second)
defer timer.Stop()
- t.controlBuf.put(&outFlowControlSizeRequest{resp})
+ t.controlBuf.put(&outFlowControlSizeRequest{resp: resp})
select {
case sz := <-resp:
return int64(sz)
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
index 3a8c36e4f9..be8ae9f9c5 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
@@ -38,11 +38,13 @@ import (
"google.golang.org/protobuf/proto"
"google.golang.org/grpc/internal"
+ "google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/grpcutil"
"google.golang.org/grpc/internal/pretty"
istatus "google.golang.org/grpc/internal/status"
"google.golang.org/grpc/internal/syscall"
+ transportinternal "google.golang.org/grpc/internal/transport/internal"
"google.golang.org/grpc/mem"
"google.golang.org/grpc/codes"
@@ -165,7 +167,13 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
}
writeBufSize := config.WriteBufferSize
readBufSize := config.ReadBufferSize
+ // The default header list size is moving from 16MB to 8KB. The 8KB limit
+ // is only used if Enable8KBDefaultHeaderListSize is true; otherwise, the
+ // old 16MB default is used. User-specified options always take precedence.
maxHeaderListSize := defaultServerMaxHeaderListSize
+ if envconfig.Enable8KBDefaultHeaderListSize {
+ maxHeaderListSize = upcomingDefaultHeaderListSize
+ }
if config.MaxHeaderListSize != nil {
maxHeaderListSize = *config.MaxHeaderListSize
}
@@ -802,7 +810,10 @@ func (t *http2Server) handleData(f *parsedDataFrame) {
dataLen := f.data.Len()
if f.Header().Flags.Has(http2.FlagDataPadded) {
if w := s.fc.onRead(size - uint32(dataLen)); w > 0 {
- t.controlBuf.put(&outgoingWindowUpdate{s.id, w})
+ t.controlBuf.put(&outgoingWindowUpdate{
+ streamID: s.id,
+ increment: w,
+ })
}
}
if dataLen > 0 {
@@ -948,8 +959,8 @@ func (t *http2Server) checkForHeaderListSize(hf []hpack.HeaderField) bool {
return false
}
}
- if sz > int64(upcomingDefaultHeaderListSize) {
- t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize)
+ if !envconfig.Enable8KBDefaultHeaderListSize && sz > int64(upcomingDefaultHeaderListSize) {
+ t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In release v1.82.0, GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE will be enabled by default, enforcing this limit.", sz, upcomingDefaultHeaderListSize)
}
return true
}
@@ -1039,7 +1050,7 @@ func (t *http2Server) writeHeaderLocked(s *ServerStream) error {
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: s.sendCompress})
}
headerFields = appendHeaderFieldsFromMD(headerFields, s.header)
- hf := &headerFrame{
+ hf := &serverHeaders{
streamID: s.id,
hf: headerFields,
endStream: false,
@@ -1107,7 +1118,7 @@ func (t *http2Server) writeStatus(s *ServerStream, st *status.Status) error {
// Attach the trailer metadata.
headerFields = appendHeaderFieldsFromMD(headerFields, s.trailer)
- trailingHeader := &headerFrame{
+ trailingHeader := &serverHeaders{
streamID: s.id,
hf: headerFields,
endStream: true,
@@ -1317,7 +1328,7 @@ func (t *http2Server) deleteStream(s *ServerStream, eosReceived bool) {
}
// finishStream closes the stream and puts the trailing headerFrame into controlbuf.
-func (t *http2Server) finishStream(s *ServerStream, rst bool, rstCode http2.ErrCode, hdr *headerFrame, eosReceived bool) {
+func (t *http2Server) finishStream(s *ServerStream, rst bool, rstCode http2.ErrCode, hdr *serverHeaders, eosReceived bool) {
// In case stream sending and receiving are invoked in separate
// goroutines (e.g., bi-directional streaming), cancel needs to be
// called to interrupt the potential blocking on other goroutines.
@@ -1441,14 +1452,14 @@ func (t *http2Server) socketMetrics() *channelz.EphemeralSocketMetrics {
func (t *http2Server) incrMsgSent() {
if channelz.IsOn() {
t.channelz.SocketMetrics.MessagesSent.Add(1)
- t.channelz.SocketMetrics.LastMessageSentTimestamp.Add(1)
+ t.channelz.SocketMetrics.LastMessageSentTimestamp.Store(transportinternal.TimeNowFunc())
}
}
func (t *http2Server) incrMsgRecv() {
if channelz.IsOn() {
t.channelz.SocketMetrics.MessagesReceived.Add(1)
- t.channelz.SocketMetrics.LastMessageReceivedTimestamp.Add(1)
+ t.channelz.SocketMetrics.LastMessageReceivedTimestamp.Store(transportinternal.TimeNowFunc())
}
}
@@ -1456,7 +1467,7 @@ func (t *http2Server) getOutFlowWindow() int64 {
resp := make(chan uint32, 1)
timer := time.NewTimer(time.Second)
defer timer.Stop()
- t.controlBuf.put(&outFlowControlSizeRequest{resp})
+ t.controlBuf.put(&outFlowControlSizeRequest{resp: resp})
select {
case sz := <-resp:
return int64(sz)
diff --git a/vendor/google.golang.org/grpc/internal/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go
index 5bbb641ad9..c34975ffef 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http_util.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go
@@ -36,6 +36,9 @@ import (
"golang.org/x/net/http2"
"golang.org/x/net/http2/hpack"
"google.golang.org/grpc/codes"
+ "google.golang.org/grpc/internal/envconfig"
+ imem "google.golang.org/grpc/internal/mem"
+ "google.golang.org/grpc/internal/transport/readyreader"
"google.golang.org/grpc/mem"
)
@@ -296,7 +299,7 @@ func decodeGrpcMessageUnchecked(msg string) string {
}
type bufWriter struct {
- pool *sync.Pool
+ pool *imem.SimpleBufferPool
buf []byte
offset int
batchSize int
@@ -304,7 +307,7 @@ type bufWriter struct {
err error
}
-func newBufWriter(conn io.Writer, batchSize int, pool *sync.Pool) *bufWriter {
+func newBufWriter(conn io.Writer, batchSize int, pool *imem.SimpleBufferPool) *bufWriter {
w := &bufWriter{
batchSize: batchSize,
conn: conn,
@@ -326,7 +329,7 @@ func (w *bufWriter) Write(b []byte) (int, error) {
return n, toIOError(err)
}
if w.buf == nil {
- b := w.pool.Get().(*[]byte)
+ b := w.pool.Get(w.batchSize)
w.buf = *b
}
written := 0
@@ -407,22 +410,32 @@ type framer struct {
errDetail error
}
-var writeBufferPoolMap = make(map[int]*sync.Pool)
-var writeBufferMutex sync.Mutex
+var ioBufferPoolMap = make(map[int]*imem.SimpleBufferPool)
+var ioBufferMutex sync.Mutex
+
+func bufferedReader(r io.Reader, bufSize int) io.Reader {
+ if bufSize <= 0 {
+ return r
+ }
+ if envconfig.EnableHTTPFramerReadBufferPooling {
+ if rr := readyreader.NewNonBlocking(r); rr != nil {
+ readPool := ioBufferPool(bufSize)
+ return readyreader.NewBuffered(rr, bufSize, readPool)
+ }
+ }
+ return bufio.NewReaderSize(r, bufSize)
+}
func newFramer(conn io.ReadWriter, writeBufferSize, readBufferSize int, sharedWriteBuffer bool, maxHeaderListSize uint32, memPool mem.BufferPool) *framer {
if writeBufferSize < 0 {
writeBufferSize = 0
}
- var r io.Reader = conn
- if readBufferSize > 0 {
- r = bufio.NewReaderSize(r, readBufferSize)
- }
- var pool *sync.Pool
+ r := bufferedReader(conn, readBufferSize)
+ var writePool *imem.SimpleBufferPool
if sharedWriteBuffer {
- pool = getWriteBufferPool(writeBufferSize)
+ writePool = ioBufferPool(writeBufferSize)
}
- w := newBufWriter(conn, writeBufferSize, pool)
+ w := newBufWriter(conn, writeBufferSize, writePool)
f := &framer{
writer: w,
fr: http2.NewFramer(w, r),
@@ -578,20 +591,15 @@ func (df *parsedDataFrame) Header() http2.FrameHeader {
return df.FrameHeader
}
-func getWriteBufferPool(size int) *sync.Pool {
- writeBufferMutex.Lock()
- defer writeBufferMutex.Unlock()
- pool, ok := writeBufferPoolMap[size]
+func ioBufferPool(size int) *imem.SimpleBufferPool {
+ ioBufferMutex.Lock()
+ defer ioBufferMutex.Unlock()
+ pool, ok := ioBufferPoolMap[size]
if ok {
return pool
}
- pool = &sync.Pool{
- New: func() any {
- b := make([]byte, size)
- return &b
- },
- }
- writeBufferPoolMap[size] = pool
+ pool = imem.NewDirtySimplePool()
+ ioBufferPoolMap[size] = pool
return pool
}
diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/regex.go b/vendor/google.golang.org/grpc/internal/transport/internal/internal.go
similarity index 59%
rename from vendor/google.golang.org/grpc/internal/grpcutil/regex.go
rename to vendor/google.golang.org/grpc/internal/transport/internal/internal.go
index 7a092b2b80..a7c7c7d5a8 100644
--- a/vendor/google.golang.org/grpc/internal/grpcutil/regex.go
+++ b/vendor/google.golang.org/grpc/internal/transport/internal/internal.go
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2021 gRPC authors.
+ * Copyright 2026 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,16 +16,10 @@
*
*/
-package grpcutil
+// Package internal contains functionality internal to the transport package.
+package internal
-import "regexp"
-
-// FullMatchWithRegex returns whether the full text matches the regex provided.
-func FullMatchWithRegex(re *regexp.Regexp, text string) bool {
- if len(text) == 0 {
- return re.MatchString(text)
- }
- re.Longest()
- rem := re.FindString(text)
- return len(rem) == len(text)
-}
+// TimeNowFunc is a variable that can be set to override the default behavior of
+// getting the current time in nanoseconds. It is used in transport code to set
+// channelz timestamps, and is exposed here for testing purposes.
+var TimeNowFunc func() int64
diff --git a/vendor/google.golang.org/grpc/internal/transport/readyreader/raw_conn_linux.go b/vendor/google.golang.org/grpc/internal/transport/readyreader/raw_conn_linux.go
new file mode 100644
index 0000000000..56906c35b3
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/transport/readyreader/raw_conn_linux.go
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2026 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package readyreader
+
+import "syscall"
+
+func isRawConnSupported() bool {
+ return true
+}
+
+// sysRead uses the standard syscall package rather than the modern unix package
+// to avoid triggering the race detector. Because both packages perform sync
+// operations on a local variable to satisfy the race detector, mixing them
+// for read and write syscalls causes data races. We use syscall here to remain
+// consistent with net.Conn implementations in standard library.
+func sysRead(fd uintptr, p []byte) (int, error) {
+ return syscall.Read(int(fd), p)
+}
+
+// wouldBlock checks standard Unix non-blocking errors.
+func wouldBlock(err error) bool {
+ return err == syscall.EAGAIN || err == syscall.EWOULDBLOCK
+}
diff --git a/vendor/google.golang.org/grpc/internal/transport/readyreader/raw_conn_nonlinux.go b/vendor/google.golang.org/grpc/internal/transport/readyreader/raw_conn_nonlinux.go
new file mode 100644
index 0000000000..4d1f330060
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/transport/readyreader/raw_conn_nonlinux.go
@@ -0,0 +1,35 @@
+//go:build !linux
+
+/*
+ *
+ * Copyright 2026 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package readyreader
+
+func isRawConnSupported() bool {
+ return false
+}
+
+// sysRead is not implemented. Support can be added in the future if necessary.
+func sysRead(uintptr, []byte) (int, error) {
+ panic("RawConn functionality is not implemented for non-unix platforms.")
+}
+
+// wouldBlock is not implemented. Support can be added in the future if necessary.
+func wouldBlock(error) bool {
+ panic("RawConn functionality is not implemented for non-unix platforms.")
+}
diff --git a/vendor/google.golang.org/grpc/internal/transport/readyreader/ready_reader.go b/vendor/google.golang.org/grpc/internal/transport/readyreader/ready_reader.go
new file mode 100644
index 0000000000..250a300c73
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/transport/readyreader/ready_reader.go
@@ -0,0 +1,253 @@
+/*
+ *
+ * Copyright 2026 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Package readyreader provides utilities to perform non-memory-pinning reads.
+package readyreader
+
+import (
+ "io"
+ "net"
+ "syscall"
+
+ "google.golang.org/grpc/mem"
+)
+
+// Reader is an optional interface that can be implemented by [net.Conn]
+// implementations to enable gRPC to perform non-memory-pinning reads.
+type Reader interface {
+ // ReadOnReady waits for data to arrive, fetches a buffer, and performs a
+ // read. When the underlying IO is readable, it allocates a buffer of size
+ // bufSize from the pool and reads up to bufSize bytes into the buffer.
+ //
+ // It returns a pointer to the buffer so it can be returned to the pool
+ // later, the number of bytes read, and an error.
+ //
+ // Callers should always process the n > 0 bytes returned before considering
+ // the error. Doing so correctly handles I/O errors that happen after
+ // reading some bytes, as well as both of the allowed EOF behaviors.
+ ReadOnReady(bufSize int, pool mem.BufferPool) (b *[]byte, n int, err error)
+}
+
+// nonBlockingReader is optimized for non-memory-pinning reads using the RawConn
+// interface.
+type nonBlockingReader struct {
+ raw syscall.RawConn
+ // The following fields are stored as field to avoid heap allocations.
+ state readState
+ doRead func(fd uintptr) bool
+}
+
+type readState struct {
+ // Request params.
+ bufSize int
+ pool mem.BufferPool
+
+ // Response params.
+ readError error
+ bytesRead int
+ buf *[]byte
+}
+
+// NewNonBlocking returns a ReadyReader if the passed reader supports
+// non-memory-pinning reads, else nil.
+func NewNonBlocking(r io.Reader) Reader {
+ if rr, ok := r.(Reader); ok {
+ return rr
+ }
+ if !isRawConnSupported() {
+ return nil
+ }
+ // We restrict the types before asserting syscall.Conn. The credentials
+ // package may return a wrapper that implements syscall.Conn by embedding
+ // both the raw connection and the encrypted connection. If the code
+ // attempts to read directly from the raw syscall.RawConn, it would read
+ // encrypted data.
+ switch r.(type) {
+ case *net.TCPConn, *net.UDPConn, *net.UnixConn, *net.IPConn:
+ default:
+ return nil
+ }
+ sysConn, ok := r.(syscall.Conn)
+ if !ok {
+ return nil
+ }
+ raw, err := sysConn.SyscallConn()
+ if err != nil {
+ return nil
+ }
+ rr := &nonBlockingReader{raw: raw}
+ rr.doRead = func(fd uintptr) bool {
+ s := &rr.state
+
+ s.buf = s.pool.Get(s.bufSize)
+ s.bytesRead, s.readError = sysRead(fd, *s.buf)
+
+ if s.readError != nil {
+ s.pool.Put(s.buf)
+ s.buf = nil
+ }
+ return !wouldBlock(s.readError)
+ }
+ return rr
+}
+
+func (c *nonBlockingReader) ReadOnReady(bufSize int, pool mem.BufferPool) (*[]byte, int, error) {
+ c.state = readState{
+ pool: pool,
+ bufSize: bufSize,
+ }
+ err := c.raw.Read(c.doRead)
+
+ buf := c.state.buf
+ n := c.state.bytesRead
+ readErr := c.state.readError
+ c.state = readState{}
+
+ if err != nil {
+ if buf != nil {
+ pool.Put(buf)
+ }
+ return nil, 0, err
+ }
+ if readErr != nil {
+ // buffer is already released in the callback.
+ return nil, 0, readErr
+ }
+ if n == 0 {
+ // syscall.Read doesn't consider a graceful socket closure to be an
+ // error condition, but Go's io.Reader expects an EOF error.
+ pool.Put(buf)
+ return nil, 0, io.EOF
+ }
+ return buf, n, nil
+}
+
+type blockingReader struct {
+ reader io.Reader
+}
+
+func (c *blockingReader) ReadOnReady(bufSize int, pool mem.BufferPool) (*[]byte, int, error) {
+ buf := pool.Get(bufSize)
+ n, err := c.reader.Read(*buf)
+ if err != nil {
+ pool.Put(buf)
+ return nil, 0, err
+ }
+ return buf, n, nil
+}
+
+// New detects if [syscall.RawConn] is available for non-memory-pinning reads.
+// If [syscall.RawConn] is unavailable, it falls back to using the simpler
+// [io.Reader] interface for reads.
+func New(r io.Reader) Reader {
+ if r := NewNonBlocking(r); r != nil {
+ return r
+ }
+ return &blockingReader{reader: r}
+}
+
+// bufReadyReader implements buffering for a ReadyReader object.
+// A new bufReadyReader is created by calling [NewBuffered].
+type bufReadyReader struct {
+ buf *[]byte
+ pool mem.BufferPool
+ bufSize int
+ rd Reader // reader provided by the caller
+ r, w int // buf read and write positions
+ err error
+ constPool constBufferPool // stored as a field to avoid heap allocations.
+}
+
+// NewBuffered returns a new [io.Reader] with a buffer of the specified size
+// which is allocated from the provided pool.
+func NewBuffered(rd Reader, size int, pool mem.BufferPool) io.Reader {
+ return &bufReadyReader{
+ rd: rd,
+ pool: pool,
+ bufSize: size,
+ }
+}
+
+func (b *bufReadyReader) readErr() error {
+ err := b.err
+ b.err = nil
+ return err
+}
+
+func (b *bufReadyReader) buffered() int { return b.w - b.r }
+
+// Read reads data into p. It returns the number of bytes read into p. The
+// bytes are taken from at most one Read on the underlying [ReadyReader],
+// hence n may be less than len(p). If the underlying [ReadyReader] can return
+// a non-zero count with io.EOF, then this Read method can do so as well; see
+// the [io.Reader] docs.
+func (b *bufReadyReader) Read(p []byte) (n int, err error) {
+ n = len(p)
+ if n == 0 {
+ if b.buffered() > 0 {
+ return 0, nil
+ }
+ return 0, b.readErr()
+ }
+ if b.r == b.w {
+ if b.err != nil {
+ return 0, b.readErr()
+ }
+ if len(p) >= b.bufSize {
+ // Large read, empty buffer.
+ // Read directly into p to avoid copy.
+ b.constPool.buffer = p
+ _, n, b.err = b.rd.ReadOnReady(len(p), &b.constPool)
+ return n, b.readErr()
+ }
+ // One read.
+ b.r = 0
+ b.w = 0
+ b.buf, n, b.err = b.rd.ReadOnReady(b.bufSize, b.pool)
+ if n == 0 {
+ if b.buf != nil {
+ b.pool.Put(b.buf)
+ b.buf = nil
+ }
+ return 0, b.readErr()
+ }
+ b.w += n
+ }
+
+ // copy as much as we can
+ // b.buf must be non-nil since b.r != b.w.
+ buf := *b.buf
+ n = copy(p, buf[b.r:b.w])
+ b.r += n
+ if b.r == b.w {
+ // Consumed entire buffer, release it.
+ b.pool.Put(b.buf)
+ b.buf = nil
+ }
+ return n, nil
+}
+
+type constBufferPool struct {
+ buffer []byte
+}
+
+func (p *constBufferPool) Get(int) *[]byte {
+ return &p.buffer
+}
+
+func (p *constBufferPool) Put(*[]byte) {}
diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go
index b86094da94..6dfae39849 100644
--- a/vendor/google.golang.org/grpc/internal/transport/transport.go
+++ b/vendor/google.golang.org/grpc/internal/transport/transport.go
@@ -31,9 +31,11 @@ import (
"sync/atomic"
"time"
+ "golang.org/x/net/http2"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/internal/channelz"
+ "google.golang.org/grpc/internal/transport/internal"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/mem"
"google.golang.org/grpc/metadata"
@@ -45,6 +47,10 @@ import (
const logLevel = 2
+func init() {
+ internal.TimeNowFunc = func() int64 { return time.Now().UnixNano() }
+}
+
// recvMsg represents the received msg from the transport. All transport
// protocol specific info has been removed.
type recvMsg struct {
@@ -742,6 +748,22 @@ const (
GoAwayTooManyPings GoAwayReason = 2
)
+// GoAwayInfo contains metadata about why a connection was closed.
+type GoAwayInfo struct {
+ // Reason is the parsed reason for an HTTP/2 GOAWAY frame.
+ Reason GoAwayReason
+ // GoAwayCode is the raw HTTP/2 error code received in a GOAWAY frame.
+ GoAwayCode http2.ErrCode
+ // Err is the underlying error that caused the connection to close. It is
+ // populated if the connection was closed due to a socket error or context
+ // cancellation without receiving a GOAWAY frame. If the connection was
+ // closed due to a GOAWAY frame, this field will be nil.
+ Err error
+}
+
+// OnCloseFunc is a callback invoked when a ClientTransport closes.
+type OnCloseFunc func(GoAwayInfo)
+
// ContextErr converts the error from context package into a status error.
func ContextErr(err error) error {
switch err {
diff --git a/vendor/google.golang.org/grpc/mem/buffer_slice.go b/vendor/google.golang.org/grpc/mem/buffer_slice.go
index 084fb19c6d..086e9f95de 100644
--- a/vendor/google.golang.org/grpc/mem/buffer_slice.go
+++ b/vendor/google.golang.org/grpc/mem/buffer_slice.go
@@ -165,7 +165,7 @@ func (r *Reader) Close() error {
}
func (r *Reader) freeFirstBufferIfEmpty() bool {
- if len(r.data) == 0 || r.bufferIdx != len(r.data[0].ReadOnlyData()) {
+ if len(r.data) == 0 || r.bufferIdx != r.data[0].Len() {
return false
}
diff --git a/vendor/google.golang.org/grpc/mem/buffers.go b/vendor/google.golang.org/grpc/mem/buffers.go
index db1620e6ac..2b410b16eb 100644
--- a/vendor/google.golang.org/grpc/mem/buffers.go
+++ b/vendor/google.golang.org/grpc/mem/buffers.go
@@ -53,6 +53,10 @@ type Buffer interface {
Free()
// Len returns the Buffer's size.
Len() int
+ // Slice returns a new Buffer that is a view into this buffer's data
+ // from [start:end). The buffer is not modified. Panics if the buffer
+ // has been freed or if start/end are out of bounds.
+ Slice(start, end int) Buffer
split(n int) (left, right Buffer)
read(buf []byte) (int, Buffer)
@@ -180,6 +184,32 @@ func (b *buffer) Len() int {
return len(b.ReadOnlyData())
}
+func (b *buffer) Slice(start, end int) Buffer {
+ if b.rootBuf == nil {
+ panic("Cannot slice freed buffer")
+ }
+
+ data := b.data[start:end] // access the data to check slice bounds
+
+ if len(data) == 0 {
+ return emptyBuffer{}
+ }
+ if len(data) == len(b.data) {
+ b.Ref()
+ return b
+ }
+ // We are creating a new reference (view) to a portion of the root buffer's
+ // data. Therefore, we must increment the reference count of the root buffer
+ // to ensure the underlying data is not freed while this view is still in
+ // use.
+ b.rootBuf.Ref()
+ s := newBuffer()
+ s.data = data
+ s.rootBuf = b.rootBuf
+ s.refs.Store(1)
+ return s
+}
+
func (b *buffer) split(n int) (Buffer, Buffer) {
if b.rootBuf == nil || b.rootBuf.refs.Add(1) <= 1 {
panic("Cannot split freed buffer")
@@ -240,6 +270,13 @@ func (e emptyBuffer) Len() int {
return 0
}
+func (e emptyBuffer) Slice(start, end int) Buffer {
+ if start != 0 || end != 0 {
+ panic(fmt.Sprintf("slice bounds out of range [%d:%d] with length 0", start, end))
+ }
+ return e
+}
+
func (e emptyBuffer) split(int) (left, right Buffer) {
return e, e
}
@@ -264,6 +301,9 @@ func (s SliceBuffer) Free() {}
// Len is a noop implementation of Len.
func (s SliceBuffer) Len() int { return len(s) }
+// Slice returns a new SliceBuffer that is a view into the receiver from [start:end).
+func (s SliceBuffer) Slice(start, end int) Buffer { return s[start:end] }
+
func (s SliceBuffer) split(n int) (left, right Buffer) {
return s[:n], s[n:]
}
diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection_grpc.pb.go b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection_grpc.pb.go
index 81ced2fbf5..21142c64e2 100644
--- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection_grpc.pb.go
+++ b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1/reflection_grpc.pb.go
@@ -21,7 +21,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
-// - protoc-gen-go-grpc v1.6.1
+// - protoc-gen-go-grpc v1.6.2
// - protoc v5.27.1
// source: grpc/reflection/v1/reflection.proto
diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go
index 18061e8ba6..2a3f45d1bc 100644
--- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go
+++ b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go
@@ -18,7 +18,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
-// - protoc-gen-go-grpc v1.6.1
+// - protoc-gen-go-grpc v1.6.2
// - protoc v5.27.1
// grpc/reflection/v1alpha/reflection.proto is a deprecated file.
diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go
index ee7f7dead1..52f4ea513d 100644
--- a/vendor/google.golang.org/grpc/rpc_util.go
+++ b/vendor/google.golang.org/grpc/rpc_util.go
@@ -128,6 +128,16 @@ func NewGZIPDecompressor() Decompressor {
}
func (d *gzipDecompressor) Do(r io.Reader) ([]byte, error) {
+ return d.doWithMaxSize(r, math.MaxInt64)
+}
+
+// doWithMaxSize behaves like Do but caps the size of the decompressed
+// payload at maxMessageSize+1 bytes. The Decompressor interface does not
+// allow extra parameters, so callers inside the package type-assert to
+// *gzipDecompressor to invoke this method directly. The +1 byte makes it
+// possible for the caller to detect that the limit was exceeded and
+// return ResourceExhausted instead of materializing an unbounded payload.
+func (d *gzipDecompressor) doWithMaxSize(r io.Reader, maxMessageSize int64) ([]byte, error) {
var z *gzip.Reader
switch maybeZ := d.pool.Get().(type) {
case nil:
@@ -148,7 +158,11 @@ func (d *gzipDecompressor) Do(r io.Reader) ([]byte, error) {
z.Close()
d.pool.Put(z)
}()
- return io.ReadAll(z)
+ var src io.Reader = z
+ if maxMessageSize < math.MaxInt64 {
+ src = io.LimitReader(z, maxMessageSize+1)
+ }
+ return io.ReadAll(src)
}
func (d *gzipDecompressor) Type() string {
@@ -830,15 +844,15 @@ func compress(in mem.BufferSlice, cp Compressor, compressor encoding.Compressor,
if compressor != nil {
z, err := compressor.Compress(w)
if err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
for _, b := range in {
if _, err := z.Write(b.ReadOnlyData()); err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
}
if err := z.Close(); err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
} else {
// This is obviously really inefficient since it fully materializes the data, but
@@ -848,7 +862,7 @@ func compress(in mem.BufferSlice, cp Compressor, compressor encoding.Compressor,
buf := in.MaterializeToBuffer(pool)
defer buf.Free()
if err := cp.Do(w, buf.ReadOnlyData()); err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
}
return out, compressionMade, nil
@@ -971,7 +985,20 @@ func recvAndDecompress(p *parser, s recvCompressor, dc Decompressor, maxReceiveM
func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompressor, maxReceiveMessageSize int, pool mem.BufferPool) (mem.BufferSlice, error) {
if dc != nil {
r := d.Reader()
- uncompressed, err := dc.Do(r)
+ // For the built-in gzip decompressor, bound the decompressed output
+ // at maxReceiveMessageSize+1 so that a small but highly compressed
+ // payload (a "zip bomb") cannot expand to gigabytes in memory before
+ // the post-decompression size check below has a chance to fire. The
+ // Decompressor interface does not accept an extra size parameter,
+ // so we type-assert to invoke a size-aware helper. Third-party
+ // Decompressor implementations keep the original Do behavior.
+ var uncompressed []byte
+ var err error
+ if gd, ok := dc.(*gzipDecompressor); ok {
+ uncompressed, err = gd.doWithMaxSize(r, int64(maxReceiveMessageSize))
+ } else {
+ uncompressed, err = dc.Do(r)
+ }
if err != nil {
r.Close() // ensure buffers are reused
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err)
@@ -989,6 +1016,9 @@ func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompress
r.Close() // ensure buffers are reused
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err)
}
+ if closer, ok := dcReader.(io.Closer); ok {
+ defer closer.Close()
+ }
// Read at most one byte more than the limit from the decompressor.
// Unless the limit is MaxInt64, in which case, that's impossible, so
diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go
index 5229adf711..cf0a206719 100644
--- a/vendor/google.golang.org/grpc/server.go
+++ b/vendor/google.golang.org/grpc/server.go
@@ -28,6 +28,7 @@ import (
"net/http"
"reflect"
"runtime"
+ "runtime/pprof"
"strings"
"sync"
"sync/atomic"
@@ -150,8 +151,6 @@ type Server struct {
serverWorkerChannel chan func()
serverWorkerChannelClose func()
-
- strictPathCheckingLogEmitted atomic.Bool
}
type serverOptions struct {
@@ -250,10 +249,8 @@ func newJoinServerOption(opts ...ServerOption) ServerOption {
// If this option is set to true every connection will release the buffer after
// flushing the data on the wire.
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a
-// later release.
+// Deprecated: shared write buffer is enabled by default. SharedWriteBuffer
+// will be removed in a future release.
func SharedWriteBuffer(val bool) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.sharedWriteBuffer = val
@@ -302,6 +299,14 @@ func InitialConnWindowSize(s int32) ServerOption {
// window size to the value provided and disables dynamic flow control.
// The lower bound for window size is 64K and any value smaller than that
// will be ignored.
+//
+// Note that this also disables dynamic flow control for the connection,
+// falling back to a default static connection-level window of 64KB. To
+// use a larger connection-level window, you must also use the
+// [StaticConnWindowSize] ServerOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func StaticStreamWindowSize(s int32) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.initialWindowSize = s
@@ -313,6 +318,14 @@ func StaticStreamWindowSize(s int32) ServerOption {
// window size to the value provided and disables dynamic flow control.
// The lower bound for window size is 64K and any value smaller than that
// will be ignored.
+//
+// Note that this also disables dynamic flow control for individual streams,
+// falling back to a default static connection-level window of 64KB. To
+// explicitly configure the stream-level window size, you must also use the
+// [StaticStreamWindowSize] ServerOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func StaticConnWindowSize(s int32) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.initialConnWindowSize = s
@@ -1787,6 +1800,12 @@ func (s *Server) handleMalformedMethodName(stream *transport.ServerStream, ti *t
func (s *Server) handleStream(t transport.ServerTransport, stream *transport.ServerStream) {
ctx := stream.Context()
ctx = contextWithServer(ctx, s)
+ if envconfig.LabelServerGoroutines&envconfig.GoroutineLabelServerMethod != 0 {
+ // This method always runs in its own goroutine, so we can set a
+ // goroutine label without needing to restore a previous context.
+ ctx = pprof.WithLabels(ctx, pprof.Labels("grpc.method", stream.Method()))
+ pprof.SetGoroutineLabels(ctx)
+ }
var ti *traceInfo
if EnableTracing {
tr := newTrace("grpc.Recv."+methodFamily(stream.Method()), stream.Method())
@@ -1803,28 +1822,11 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Ser
}
}
- sm := stream.Method()
- if sm == "" {
+ sm, found := strings.CutPrefix(stream.Method(), "/")
+ if !found {
s.handleMalformedMethodName(stream, ti)
return
}
- if sm[0] != '/' {
- // TODO(easwars): Add a link to the CVE in the below log messages once
- // published.
- if envconfig.DisableStrictPathChecking {
- if old := s.strictPathCheckingLogEmitted.Swap(true); !old {
- channelz.Warningf(logger, s.channelz, "grpc: Server.handleStream received malformed method name %q. Allowing it because the environment variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING is set to true, but this option will be removed in a future release.", sm)
- }
- } else {
- if old := s.strictPathCheckingLogEmitted.Swap(true); !old {
- channelz.Warningf(logger, s.channelz, "grpc: Server.handleStream rejected malformed method name %q. To temporarily allow such requests, set the environment variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to true. Note that this is not recommended as it may allow requests to bypass security policies.", sm)
- }
- s.handleMalformedMethodName(stream, ti)
- return
- }
- } else {
- sm = sm[1:]
- }
pos := strings.LastIndex(sm, "/")
if pos == -1 {
s.handleMalformedMethodName(stream, ti)
diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go
index eedb5f9b99..4aac644a83 100644
--- a/vendor/google.golang.org/grpc/stream.go
+++ b/vendor/google.golang.org/grpc/stream.go
@@ -21,6 +21,7 @@ package grpc
import (
"context"
"errors"
+ "fmt"
"io"
"math"
rand "math/rand/v2"
@@ -749,7 +750,7 @@ func (a *csAttempt) shouldRetry(err error) (bool, error) {
return false, err
}
if cs.numRetries+1 >= rp.MaxAttempts {
- return false, err
+ return false, fmt.Errorf("max retries exhausted: failed after %d attempts: %w", cs.numRetries+1, err)
}
var dur time.Duration
diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go
index 12f649dcb7..53c737feeb 100644
--- a/vendor/google.golang.org/grpc/version.go
+++ b/vendor/google.golang.org/grpc/version.go
@@ -19,4 +19,4 @@
package grpc
// Version is the current grpc version.
-const Version = "1.80.0"
+const Version = "1.82.1"
diff --git a/vendor/modules.txt b/vendor/modules.txt
index f36065d39e..796d65182e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,14 +1,14 @@
-# charm.land/bubbles/v2 v2.1.0
+# charm.land/bubbles/v2 v2.1.1
## explicit; go 1.25.0
charm.land/bubbles/v2/cursor
charm.land/bubbles/v2/internal/runeutil
charm.land/bubbles/v2/key
charm.land/bubbles/v2/textinput
charm.land/bubbles/v2/viewport
-# charm.land/bubbletea/v2 v2.0.2
-## explicit; go 1.24.2
+# charm.land/bubbletea/v2 v2.0.7
+## explicit; go 1.25.0
charm.land/bubbletea/v2
-# charm.land/lipgloss/v2 v2.0.2
+# charm.land/lipgloss/v2 v2.0.4
## explicit; go 1.25.0
charm.land/lipgloss/v2
# charm.land/log/v2 v2.0.0
@@ -46,10 +46,10 @@ github.com/charmbracelet/keygen
# github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309
## explicit; go 1.23.0
github.com/charmbracelet/ssh
-# github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8
-## explicit; go 1.24.2
+# github.com/charmbracelet/ultraviolet v0.0.0-20260525132238-948f4557a654
+## explicit; go 1.25.0
github.com/charmbracelet/ultraviolet
-# github.com/charmbracelet/x/ansi v0.11.6
+# github.com/charmbracelet/x/ansi v0.11.7
## explicit; go 1.24.2
github.com/charmbracelet/x/ansi
github.com/charmbracelet/x/ansi/kitty
@@ -69,16 +69,18 @@ github.com/charmbracelet/x/termios
# github.com/charmbracelet/x/windows v0.2.2
## explicit; go 1.23.0
github.com/charmbracelet/x/windows
-# github.com/cilium/ebpf v0.19.0
-## explicit; go 1.23.0
+# github.com/cilium/ebpf v0.22.0
+## explicit; go 1.25.0
github.com/cilium/ebpf
github.com/cilium/ebpf/asm
github.com/cilium/ebpf/btf
+github.com/cilium/ebpf/features
github.com/cilium/ebpf/internal
github.com/cilium/ebpf/internal/efw
github.com/cilium/ebpf/internal/kallsyms
github.com/cilium/ebpf/internal/kconfig
github.com/cilium/ebpf/internal/linux
+github.com/cilium/ebpf/internal/mountinfo
github.com/cilium/ebpf/internal/platform
github.com/cilium/ebpf/internal/sys
github.com/cilium/ebpf/internal/sysenc
@@ -96,7 +98,7 @@ github.com/clipperhouse/uax29/v2/graphemes
# github.com/creack/pty v1.1.24
## explicit; go 1.18
github.com/creack/pty
-# github.com/davecgh/go-spew v1.1.1
+# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
## explicit
github.com/davecgh/go-spew/spew
# github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
@@ -109,7 +111,7 @@ github.com/fsnotify/fsnotify/internal
# github.com/ftrvxmtrx/fd v0.0.0-20150925145434-c6d800382fff
## explicit
github.com/ftrvxmtrx/fd
-# github.com/gaissmai/bart v0.26.1
+# github.com/gaissmai/bart v0.29.0
## explicit; go 1.24.0
github.com/gaissmai/bart
github.com/gaissmai/bart/internal/allot
@@ -203,7 +205,7 @@ github.com/klauspost/compress/internal/le
github.com/klauspost/compress/internal/snapref
github.com/klauspost/compress/zstd
github.com/klauspost/compress/zstd/internal/xxhash
-# github.com/lucasb-eyer/go-colorful v1.3.0
+# github.com/lucasb-eyer/go-colorful v1.4.0
## explicit; go 1.12
github.com/lucasb-eyer/go-colorful
# github.com/lunixbochs/struc v0.0.0-20200521075829-a4cb8d33dbbe
@@ -212,22 +214,22 @@ github.com/lunixbochs/struc
# github.com/mattn/go-isatty v0.0.22
## explicit; go 1.21
github.com/mattn/go-isatty
-# github.com/mattn/go-runewidth v0.0.21
+# github.com/mattn/go-runewidth v0.0.24
## explicit; go 1.20
github.com/mattn/go-runewidth
-# github.com/mdlayher/genetlink v1.3.2
-## explicit; go 1.18
+# github.com/mdlayher/genetlink v1.4.0
+## explicit; go 1.25.0
github.com/mdlayher/genetlink
-# github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42
-## explicit; go 1.21
+# github.com/mdlayher/netlink v1.9.0
+## explicit; go 1.24.0
github.com/mdlayher/netlink
github.com/mdlayher/netlink/nlenc
github.com/mdlayher/netlink/nltest
# github.com/mdlayher/packet v1.1.2
## explicit; go 1.20
github.com/mdlayher/packet
-# github.com/mdlayher/socket v0.5.1
-## explicit; go 1.20
+# github.com/mdlayher/socket v0.6.0
+## explicit; go 1.25.0
github.com/mdlayher/socket
# github.com/miekg/dns v1.1.72
## explicit; go 1.24.0
@@ -259,11 +261,11 @@ github.com/pierrec/lz4/v4/internal/lz4block
github.com/pierrec/lz4/v4/internal/lz4errors
github.com/pierrec/lz4/v4/internal/lz4stream
github.com/pierrec/lz4/v4/internal/xxh32
-# github.com/pmezard/go-difflib v1.0.0
+# github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
## explicit
github.com/pmezard/go-difflib/difflib
-# github.com/prometheus/client_golang v1.23.2
-## explicit; go 1.23.0
+# github.com/prometheus/client_golang v1.24.0
+## explicit; go 1.25.0
github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil
github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header
github.com/prometheus/client_golang/prometheus
@@ -274,20 +276,20 @@ github.com/prometheus/client_golang/prometheus/promhttp/internal
# github.com/prometheus/client_model v0.6.2
## explicit; go 1.22.0
github.com/prometheus/client_model/go
-# github.com/prometheus/common v0.66.1
-## explicit; go 1.23.0
+# github.com/prometheus/common v0.70.0
+## explicit; go 1.25.0
github.com/prometheus/common/expfmt
github.com/prometheus/common/model
-# github.com/prometheus/procfs v0.16.1
-## explicit; go 1.23.0
+# github.com/prometheus/procfs v0.21.1
+## explicit; go 1.25.0
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/rivo/uniseg v0.4.7
## explicit; go 1.18
github.com/rivo/uniseg
-# github.com/sirupsen/logrus v1.9.3
-## explicit; go 1.13
+# github.com/sirupsen/logrus v1.9.4
+## explicit; go 1.17
github.com/sirupsen/logrus
# github.com/sivchari/gomu v0.2.1
## explicit; go 1.24
@@ -362,10 +364,7 @@ go.fd.io/govpp/binapi/wireguard
go.fd.io/govpp/codec
go.fd.io/govpp/core
go.fd.io/govpp/core/genericpool
-# go.yaml.in/yaml/v2 v2.4.2
-## explicit; go 1.15
-go.yaml.in/yaml/v2
-# golang.org/x/crypto v0.53.0
+# golang.org/x/crypto v0.54.0
## explicit; go 1.25.0
golang.org/x/crypto/argon2
golang.org/x/crypto/bcrypt
@@ -396,7 +395,7 @@ golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
golang.org/x/mod/module
golang.org/x/mod/semver
-# golang.org/x/net v0.56.0
+# golang.org/x/net v0.57.0
## explicit; go 1.25.0
golang.org/x/net/bpf
golang.org/x/net/http/httpguts
@@ -415,31 +414,31 @@ golang.org/x/net/trace
## explicit; go 1.25.0
golang.org/x/oauth2
golang.org/x/oauth2/internal
-# golang.org/x/sync v0.21.0
+# golang.org/x/sync v0.22.0
## explicit; go 1.25.0
golang.org/x/sync/errgroup
-# golang.org/x/sys v0.46.0
+# golang.org/x/sys v0.47.0
## explicit; go 1.25.0
golang.org/x/sys/cpu
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/telemetry v0.0.0-20260508192327-42602be52be6
+# golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57
## explicit; go 1.25.0
golang.org/x/telemetry/counter
golang.org/x/telemetry/internal/counter
golang.org/x/telemetry/internal/mmap
golang.org/x/telemetry/internal/telemetry
-# golang.org/x/term v0.44.0
+# golang.org/x/term v0.45.0
## explicit; go 1.25.0
golang.org/x/term
-# golang.org/x/text v0.38.0
+# golang.org/x/text v0.40.0
## explicit; go 1.25.0
golang.org/x/text/secure/bidirule
golang.org/x/text/transform
golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm
-# golang.org/x/tools v0.45.0
+# golang.org/x/tools v0.47.0
## explicit; go 1.25.0
golang.org/x/tools/cmd/goimports
golang.org/x/tools/go/ast/astutil
@@ -481,11 +480,11 @@ golang.zx2c4.com/wireguard/wgctrl/internal/wguser
golang.zx2c4.com/wireguard/wgctrl/internal/wgwindows
golang.zx2c4.com/wireguard/wgctrl/internal/wgwindows/internal/ioctl
golang.zx2c4.com/wireguard/wgctrl/wgtypes
-# google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516
-## explicit; go 1.24.0
+# google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478
+## explicit; go 1.25.0
google.golang.org/genproto/googleapis/rpc/status
-# google.golang.org/grpc v1.80.0
-## explicit; go 1.24.0
+# google.golang.org/grpc v1.82.1
+## explicit; go 1.25.0
google.golang.org/grpc
google.golang.org/grpc/attributes
google.golang.org/grpc/backoff
@@ -505,13 +504,13 @@ google.golang.org/grpc/credentials/insecure
google.golang.org/grpc/encoding
google.golang.org/grpc/encoding/internal
google.golang.org/grpc/encoding/proto
+google.golang.org/grpc/experimental/balancer/weight
google.golang.org/grpc/experimental/stats
google.golang.org/grpc/grpclog
google.golang.org/grpc/grpclog/internal
google.golang.org/grpc/internal
google.golang.org/grpc/internal/backoff
google.golang.org/grpc/internal/balancer/gracefulswitch
-google.golang.org/grpc/internal/balancer/weight
google.golang.org/grpc/internal/balancerload
google.golang.org/grpc/internal/binarylog
google.golang.org/grpc/internal/buffer
@@ -537,7 +536,9 @@ google.golang.org/grpc/internal/stats
google.golang.org/grpc/internal/status
google.golang.org/grpc/internal/syscall
google.golang.org/grpc/internal/transport
+google.golang.org/grpc/internal/transport/internal
google.golang.org/grpc/internal/transport/networktype
+google.golang.org/grpc/internal/transport/readyreader
google.golang.org/grpc/keepalive
google.golang.org/grpc/mem
google.golang.org/grpc/metadata
@@ -552,8 +553,8 @@ google.golang.org/grpc/serviceconfig
google.golang.org/grpc/stats
google.golang.org/grpc/status
google.golang.org/grpc/tap
-# google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1
-## explicit; go 1.24.0
+# google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.2
+## explicit; go 1.25.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc
# google.golang.org/protobuf v1.36.11
## explicit; go 1.23