code: func (service *GCSService) compose(ctx context.Context, bucket string, srcs []string, dst string) error {
  	dstParams := GCSObjectParams{
  		Bucket: bucket,
  		ID:     dst,
  	}
  	objSrcs := make([]*storage.ObjectHandle, len(srcs))
  	var crc uint32
  	for i := 0; i < len(srcs); i++ {
  		objSrcs[i] = service.Client.Bucket(bucket).Object(srcs[i])
  		srcAttrs, err := service.GetObjectAttrs(ctx, GCSObjectParams{
  			Bucket: bucket,
  			ID:     srcs[i],
  		})
  		if err != nil {
  			return err
  		}
  
  		if i == 0 {
  			crc = srcAttrs.CRC32C
  		} else {
  			crc = crc32combine.CRC32Combine(crc32.Castagnoli, crc, srcAttrs.CRC32C, srcAttrs.Size)
  		}
  	}
  
  	attrs, err := service.GetObjectAttrs(ctx, GCSObjectParams{
  		Bucket: bucket,
  		ID:     srcs[0],
  	})
  	if err != nil {
  		return err
  	}
  
  	for i := 0; i < COMPOSE_RETRIES; i++ {
  		dstCRC, err := service.ComposeFrom(ctx, objSrcs, dstParams, attrs.ContentType)
  		if err != nil {
  			return err
  		}
  
  		if dstCRC == crc {
  			return nil
  		}
  	}
  
  	err = service.DeleteObject(ctx, GCSObjectParams{
  		Bucket: bucket,
  		ID:     dst,
  	})
  
  	if err != nil {
  		return err
  	}
  
  	err = errors.New("GCS compose failed: Mismatch of CRC32 checksums")
  	return err
  }
docs: // Compose takes a bucket name, a list of initial source names, and a destination string to compose multiple GCS objects together