github.com/ipld/go-ipld-prime@v0.21.0/storage/doc.go (about)

     1  // The storage package contains interfaces for storage systems, and functions for using them.
     2  //
     3  // These are very low-level storage primitives.
     4  // The interfaces here deal only with raw keys and raw binary blob values.
     5  //
     6  // In IPLD, you can often avoid dealing with storage directly yourself,
     7  // and instead use linking.LinkSystem to handle serialization, hashing, and storage all at once.
     8  // (You'll hand some values that match interfaces from this package to LinkSystem when configuring it.)
     9  // It's probably best to work at that level and above as much as possible.
    10  // If you do need to interact with storage more directly, the read on.
    11  //
    12  // The most basic APIs are ReadableStorage and WritableStorage.
    13  // When writing code that works with storage systems, these two interfaces should be seen in almost all situations:
    14  // user code is recommended to think in terms of these types;
    15  // functions provided by this package will accept parameters of these types and work on them;
    16  // implementations are expected to provide these types first;
    17  // and any new library code is recommended to keep with the theme: use these interfaces preferentially.
    18  //
    19  // Users should decide which actions they want to take using a storage system,
    20  // find the appropriate function in this package (n.b., package function -- not a method on an interface!
    21  // You will likely find one of each, with the same name: pick the package function!),
    22  // and use that function, providing it the storage system (e.g. either ReadableStorage, WritableStorage, or sometimes just Storage)
    23  // as a parameter.
    24  // That function will then use feature-detection (checking for matches to the other,
    25  // more advanced and more specific interfaces in this package) and choose the best way
    26  // to satisfy the request; or, if it can't feature-detect any relevant features,
    27  // the function will fall back to synthesizing the requested behavior out of the most basic API.
    28  // Using the package functions, and letting them do the feature detection for you,
    29  // should provide the most consistent user experience and minimize the amount of work you need to do.
    30  // (Bonus: It also gives us a convenient place to smooth out any future library migrations for you!)
    31  //
    32  // If writing new APIs that are meant to work reusably for any storage implementation:
    33  // APIs should usually be designed around accepting ReadableStorage or WritableStorage as parameters
    34  // (depending on which direction of data flow the API is regarding).
    35  // and use the other interfaces (e.g. StreamingReadableStorage) thereafter internally for feature detection.
    36  // For APIs which may sometimes be found relating to either a read or a write direction of data flow,
    37  // the Storage interface may be used in order to define a function that should accept either ReadableStorage or WritableStorage.
    38  // In other words: when writing reusable APIs, one should follow the same pattern as this package's own functions do.
    39  //
    40  // Similarly, implementers of storage systems should always implement either ReadableStorage or WritableStorage first.
    41  // Only after satisfying one of those should the implementation then move on to further supporting
    42  // additional interfaces in this package (all of which are meant to support feature-detection).
    43  // Beyond one of the basic two, all the other interfaces are optional:
    44  // you can implement them if you want to advertise additional features,
    45  // or advertise fastpaths that your storage system supports;
    46  // but you don't have implement any of those additional interfaces if you don't want to,
    47  // or if your implementation can't offer useful fastpaths for them.
    48  //
    49  // Storage systems as described by this package are allowed to make some interesting trades.
    50  // Generally, write operations are allowed to be first-write-wins.
    51  // Furthermore, there is no requirement that the system return an error if a subsequent write to the same key has different content.
    52  // These rules are reasonable for a content-addressed storage system, and allow great optimizations to be made.
    53  //
    54  // Note that all of the interfaces in this package only use types that are present in the golang standard library.
    55  // This is intentional, and was done very carefully.
    56  // If implementing a storage system, you should find it possible to do so *without* importing this package.
    57  // Because only standard library types are present in the interface contracts,
    58  // it's possible to implement types that align with the interfaces without refering to them.
    59  //
    60  // Note that where keys are discussed in this package, they use the golang string type --
    61  // however, they may be binary.  (The golang string type allows arbitrary bytes in general,
    62  // and here, we both use that, and explicitly disavow the usual "norm" that the string type implies UTF-8.
    63  // This is roughly the same as the practical truth that appears when using e.g. os.OpenFile and other similar functions.)
    64  // If you are creating a storage implementation where the underlying medium does not support arbitrary binary keys,
    65  // then it is strongly recommend that your storage implementation should support being configured with
    66  // an "escaping function", which should typically simply be of the form `func(string) string`.
    67  // Additional, your storage implementation's documentation should also clearly describe its internal limitations,
    68  // so that users have enough information to write an escaping function which
    69  // maps their domain into the domain your storage implementation can handle.
    70  package storage
    71  
    72  // also note:
    73  // LinkContext stays *out* of this package.  It's a chooser-related thing.
    74  // LinkSystem can think about it (and your callbacks over there can think about it), and that's the end of its road.
    75  // (Future: probably LinkSystem should have SetStorage and SetupStorageChooser methods for helping you set things up -- where the former doesn't discuss LinkContext at all.)