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) }