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  }