github.com/quay/claircore@v1.5.28/internal/wart/layerdescription.go (about) 1 package wart 2 3 import ( 4 "github.com/quay/claircore" 5 ) 6 7 // BUG(hank) There's currently extra copies between [claircore.Layer] and 8 // [claircore.LayerDescription] because of the original sin of making the 9 // internal layer object also the external layer description. In the future, the 10 // external API should not accept [claircore.Layer] and instead deal in 11 // [claircore.LayerDescription]. 12 13 // LayersToDescriptions takes a slice of [claircore.Layer] pointers and creates 14 // equivalent [claircore.LayerDescription]s. 15 // 16 // This is a helper for shims from a previous API that takes a [claircore.Layer] 17 // pointer slice to a new one that takes a [claircore.LayerDescription] slice. 18 // 19 // If the previous API is expected to mutate the [claircore.Layer] pointers, 20 // make sure to call [CopyLayerPointers] to ensure the correct values end up in 21 // the original slice. 22 func LayersToDescriptions(ls []*claircore.Layer) (ds []claircore.LayerDescription) { 23 ds = make([]claircore.LayerDescription, len(ls)) 24 for i, l := range ls { 25 d := &ds[i] 26 d.MediaType = `application/vnd.oci.image.layer.v1.tar` 27 d.Digest = l.Hash.String() 28 d.URI = l.URI 29 d.Headers = make(map[string][]string, len(l.Headers)) 30 for k, v := range l.Headers { 31 c := make([]string, len(v)) 32 copy(c, v) 33 d.Headers[k] = c 34 } 35 } 36 return ds 37 } 38 39 // DescriptionsToLayers takes a slice of [claircore.LayerDescription]s and 40 // creates equivalent [claircore.Layer] pointers. 41 // 42 // This is a helper for shims from a new API that takes a 43 // [claircore.LayerDescription] slice to a previous API that takes a 44 // [claircore.Layer] pointer slice. 45 func DescriptionsToLayers(ds []claircore.LayerDescription) []*claircore.Layer { 46 // Set up return slice. 47 ls := make([]claircore.Layer, len(ds)) 48 ret := make([]*claircore.Layer, len(ds)) 49 for i := range ls { 50 ret[i] = &ls[i] 51 } 52 // Populate the Layers. 53 for i := range ds { 54 d, l := &ds[i], ret[i] 55 l.Hash = claircore.MustParseDigest(d.Digest) 56 l.URI = d.URI 57 l.Headers = make(map[string][]string, len(d.Headers)) 58 for k, v := range d.Headers { 59 c := make([]string, len(v)) 60 copy(c, v) 61 l.Headers[k] = c 62 } 63 } 64 return ret 65 } 66 67 // CopyLayerPointers ensures that "dst" ends up with pointers to the equivalent 68 // [claircore.Layer]s (as determined by [claircore.Layer.Hash] equality) in 69 // "src". 70 // 71 // This function is O(n²), so if one can prove that "src" is unmodified without 72 // walking both slices, the call to this function should be omitted. 73 // 74 // Needing to use this indicates the API that's being shimmed has subtle state 75 // assumptions and should really be redesigned. 76 func CopyLayerPointers[L LayerOrPointer](dst []*claircore.Layer, src []L) { 77 if len(src) == 0 { 78 return 79 } 80 var z L 81 for i := range src { 82 for j, a := range dst { 83 var b *claircore.Layer 84 switch any(z).(type) { 85 case claircore.Layer: 86 b = any(&src[i]).(*claircore.Layer) 87 case *claircore.Layer: 88 b = any(src[i]).(*claircore.Layer) 89 default: 90 panic("unreachable") 91 } 92 if a.Hash.String() == b.Hash.String() { 93 dst[j] = b 94 } 95 } 96 } 97 } 98 99 // LayerOrPointer abstracts over a [claircore.Layer] or a pointer to a 100 // [claircore.Layer]. A user of this type will still need to do runtime 101 // reflection due to the lack of sum types. 102 type LayerOrPointer interface { 103 claircore.Layer | *claircore.Layer 104 }