github.com/ipld/go-ipld-prime@v0.21.0/storage/memstore/memstore.go (about) 1 package memstore 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io" 8 ) 9 10 // Store is a simple in-memory storage. 11 // (It's little more than a map -- in fact, the map is exported, 12 // and you can poke it directly.) 13 // 14 // Store conforms to the storage.ReadableStorage and storage.WritableStorage APIs. 15 // Additionally, it supports storage.PeekableStorage and storage.StreamingReadableStorage, 16 // because it can do so while provoking fewer copies. 17 // 18 // If you want to use this store with streaming APIs, 19 // you can still do so by using the functions in the storage package, 20 // such as storage.GetStream and storage.PutStream, which will synthesize the correct behavior. 21 // 22 // You can use this storage with a linking.LinkSystem easily, 23 // by using the LinkSystem.SetReadStorage and/or LinkSystem.SetWriteStorage methods. 24 // 25 // There are no construction parameters for sharding functions nor escaping functions. 26 // Any keys are acceptable. 27 // 28 // This storage is mostly expected to be used for testing and demos, 29 // and as an example of how you can implement and integrate your own storage systems. 30 // It does not provide persistence beyond memory. 31 type Store struct { 32 Bag map[string][]byte 33 } 34 35 func (store *Store) beInitialized() { 36 if store.Bag != nil { 37 return 38 } 39 store.Bag = make(map[string][]byte) 40 } 41 42 // Has implements go-ipld-prime/storage.Storage.Has. 43 func (store *Store) Has(ctx context.Context, key string) (bool, error) { 44 if store.Bag == nil { 45 return false, nil 46 } 47 _, exists := store.Bag[key] 48 return exists, nil 49 } 50 51 // Get implements go-ipld-prime/storage.ReadableStorage.Get. 52 // 53 // Note that this internally performs a defensive copy; 54 // use Peek for higher performance if you are certain you won't mutate the returned slice. 55 func (store *Store) Get(ctx context.Context, key string) ([]byte, error) { 56 store.beInitialized() 57 content, exists := store.Bag[key] 58 if !exists { 59 return nil, fmt.Errorf("404") // FIXME this needs a standard error type 60 } 61 cpy := make([]byte, len(content)) 62 copy(cpy, content) 63 return cpy, nil 64 } 65 66 // Put implements go-ipld-prime/storage.WritableStorage.Put. 67 func (store *Store) Put(ctx context.Context, key string, content []byte) error { 68 store.beInitialized() 69 if _, exists := store.Bag[key]; exists { 70 return nil 71 } 72 cpy := make([]byte, len(content)) 73 copy(cpy, content) 74 store.Bag[key] = cpy 75 return nil 76 } 77 78 // GetStream implements go-ipld-prime/storage.StreamingReadableStorage.GetStream. 79 // 80 // It's useful for this storage implementation to explicitly support this, 81 // because returning a reader gives us room to avoid needing a defensive copy. 82 func (store *Store) GetStream(ctx context.Context, key string) (io.ReadCloser, error) { 83 content, exists := store.Bag[key] 84 if !exists { 85 return nil, fmt.Errorf("404") // FIXME this needs a standard error type 86 } 87 return noopCloser{bytes.NewReader(content)}, nil 88 } 89 90 // Peek implements go-ipld-prime/storage.PeekableStorage.Peek. 91 func (store *Store) Peek(ctx context.Context, key string) ([]byte, io.Closer, error) { 92 content, exists := store.Bag[key] 93 if !exists { 94 return nil, nil, fmt.Errorf("404") // FIXME this needs a standard error type 95 } 96 return content, noopCloser{nil}, nil 97 } 98 99 type noopCloser struct { 100 io.Reader 101 } 102 103 func (noopCloser) Close() error { return nil }