github.com/creachadair/ffs@v0.17.3/file/wiretype/types.go (about)

     1  // Copyright 2020 Michael J. Fromberger. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package wiretype defines the encoding types for the ffs package.
    16  // Most of this package is generated by the protocol buffer compiler from the
    17  // schema in file/wiretype/wiretype.proto.
    18  package wiretype
    19  
    20  //go:generate go install google.golang.org/protobuf/cmd/protoc-gen-go
    21  //go:generate protoc -I. -I../.. --go_out=. --go_opt=paths=source_relative wiretype.proto
    22  
    23  import (
    24  	"context"
    25  	"fmt"
    26  	"sort"
    27  
    28  	"google.golang.org/protobuf/encoding/protojson"
    29  	"google.golang.org/protobuf/proto"
    30  )
    31  
    32  // MarshalJSON implements the json.Marshaler interface for a *Node, by
    33  // delegating to the protojson marshaler. This allows a node to be encoded
    34  // using the encoding/json package transparently.
    35  func (n *Node) MarshalJSON() ([]byte, error) { return protojson.Marshal(n) }
    36  
    37  // MarshalJSON implements the json.Marshaler interface for a *Root, by
    38  // delegating to the protojson marshaler. This allows a node to be encoded
    39  // using the encoding/json package transparently.
    40  func (r *Root) MarshalJSON() ([]byte, error) { return protojson.Marshal(r) }
    41  
    42  // Normalize updates n in-place so that all fields are in canonical order.
    43  func (n *Node) Normalize() {
    44  	n.Index.Normalize()
    45  	sort.Slice(n.XAttrs, func(i, j int) bool {
    46  		return n.XAttrs[i].Name < n.XAttrs[j].Name
    47  	})
    48  	sort.Slice(n.Children, func(i, j int) bool {
    49  		return n.Children[i].Name < n.Children[j].Name
    50  	})
    51  }
    52  
    53  // Normalize updates n in-place so that all fields are in canonical order.
    54  func (x *Index) Normalize() {
    55  	if x == nil || len(x.Extents) == 0 {
    56  		return
    57  	}
    58  	sort.Slice(x.Extents, func(i, j int) bool {
    59  		return x.Extents[i].Base < x.Extents[j].Base
    60  	})
    61  	i, j := 0, 1
    62  	for j < len(x.Extents) {
    63  		if x.Extents[i].Bytes == 0 {
    64  			// Remove empty extents.
    65  			x.Extents[i] = x.Extents[j]
    66  		} else if x.Extents[i].Base+x.Extents[i].Bytes == x.Extents[j].Base {
    67  			// If two adjacent extents abut, merge them into the first.
    68  			x.Extents[i].Bytes += x.Extents[j].Bytes
    69  			x.Extents[i].Blocks = append(x.Extents[i].Blocks, x.Extents[j].Blocks...)
    70  		} else {
    71  			i++
    72  			x.Extents[i] = x.Extents[j]
    73  		}
    74  		j++
    75  	}
    76  
    77  	// Do an empty check on the sole or trailing extent.
    78  	if x.Extents[i].Bytes == 0 {
    79  		i--
    80  	}
    81  	x.Extents = x.Extents[:i+1]
    82  }
    83  
    84  // Getter is the interface to storage used by the Load function.
    85  type Getter interface {
    86  	Get(context.Context, string) ([]byte, error)
    87  }
    88  
    89  // Putter is the interface to storage used by the Save function.
    90  type Putter interface {
    91  	CASPut(context.Context, []byte) (string, error)
    92  }
    93  
    94  // Load reads the specified blob from s and decodes it into msg.
    95  func Load(ctx context.Context, s Getter, key string, msg proto.Message) error {
    96  	bits, err := s.Get(ctx, key)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	return proto.Unmarshal(bits, msg)
   101  }
   102  
   103  // Save encodes msg in wire format and writes it to s, returning the storage key.
   104  func Save(ctx context.Context, s Putter, msg proto.Message) (string, error) {
   105  	bits, err := proto.Marshal(msg)
   106  	if err != nil {
   107  		return "", fmt.Errorf("encode: %w", err)
   108  	}
   109  	return s.CASPut(ctx, bits)
   110  }
   111  
   112  // ToBinary encodes msg in wire format and returns the bytes.
   113  // This is a wrapper around proto.Marshal so the caller does not need to
   114  // directly import the protobuf machinery.
   115  func ToBinary(msg proto.Message) ([]byte, error) { return proto.Marshal(msg) }