feat: add serde

Adds serialization/deserialization support via serde and serde_with.

Also:

- remove `license-file` in Cargo.toml (superfluous)
- update README with Getting Started section
- add `serde` and `serde_with` dependencies to README
- add tests to `HeightVector`
- tweak assertion in `NetworkCoordinate`
- refactor `Vector` to be a struct witn an `inner` instead of a tuple struct so that we can use `serde_as` (from `serde_with`) to help us derive SerDe implementations for the const generic sized array
- moved trait requirements (which are getting long) into where clauses

Signed-off-by: Stephen Waits <steve@waits.net>
This commit is contained in:
swaits committed 2023-02-04 09:42:46 -07:00
1 parent 9265b5fa28
commit b3147dfad7
5 files changed
+213 -34

No files matched your search

+64 -13
View File
@@ -10,7 +10,7 @@ other will be close to each other. Nodes with high latency between them will be
far from each other.
This is an implementation of Vivaldi Network Coordinates, a specific NC
algorithm, with a public simple interface and few dependencies. Vivaldi
algorithm, with a simple simple interface and few dependencies. Vivaldi
coordinates are typically used in distributed networking applications, like p2p
networks. They allow each node in the network to estimate its position in a
latency space in a distributed way, with no central authority. This enables
@@ -62,6 +62,51 @@ Regarding the two drawbacks mentioned by the Wikiepedia article, quoted above:
### Getting Started
Add the crate to your project:
```bash
cargo add vivaldi-nc
```
Each node in the network should create a `NetworkCoordinate` (NC). The node
uses this structure to track its latency position in the entire network.
```rust
use vivaldi_nc::network_coordinate::NetworkCoordinate;
// create a 2-dimensional NetworkCoordinate to track my position
let mut my_position = NetworkCoordinate::<2>::new();
```
Normally 2 or 3-dimensions is plenty. Higher dimensions may add some accuracy,
but not enough to be worth the extra costs.
Each node occasionally sends its NC to other nodes. Upon receiving a NC from a
remote node, update your local node's position with the actual measured ping
time to that node.
```rust
my_position.update(&remote_position, Duration::from_millis(measured_rtt));
```
Over time your NC will get more and more accurate as it's updated against more
nodes in the network.
You can estimate your ping time with any other NC you receive, even if it was
forwarded to you indirectly.
```rust
let rtt_estimate = my_position.estimate_rtt(&remote_position);
```
That's the entire interface for creating and iteratively updating NCs.
If you want to save/restore NCs, or send/receive them over a network, you'll
want to serialize/deserialize them. `NetworkCoordinate` supports
[Serde](https://crates.io/crates/serde) by default. Many formats are supported
by Serde, including text formats like [JSON](https://github.com/serde-rs/json)
and compact binary formats like [bincode](https://crates.io/crates/bincode) and
[MessagePack](https://github.com/3Hren/msgpack-rust).
### Features
### Examples
@@ -72,13 +117,19 @@ One design goal of this crate is to minimize dependencies. When dependencies
are required, I try to be very selective about them (re: bloat and licensing).
This crate depends on:
- `nanorand`: A fast PRNG based on WyRand. It pulls in `getrandom` as a
portable source of entropy. I chose this over the more commonly used, but
heavyweight `rand` because it's significantly smaller and does just what I
need, and not much more.
- `num-traits`: A brilliant crate which makes it easier to operate on numbers
in generics; like using `Float` as a constraint on a generic type. Its
convenience outweighs its cost.
- [`nanorand`](https://crates.io/crates/nanorand): A fast PRNG based on WyRand.
It pulls in `getrandom` as a portable source of entropy. I chose this over
the more commonly used, but heavyweight `rand` because it's significantly
smaller and does just what I need, and not much more.
- [`num-traits`](https://crates.io/crates/num-traits): A brilliant crate which
makes it easier to operate on numbers in generics; like using `Float` as a
constraint on a generic type. Its convenience outweighs its cost.
- [`serde`](https://crates.io/crates/serde): I think NCs are usually meant to
be shared across a network. That requires serialization/deserialization and
serde is *the* choice for that. It might be big, but it's efficient.
- [`serde_with`](https://crates.io/crates/serde_with): Because the inner
`Vector<T,N>` uses a const generic length, we use this to help derive
`Deserialize`.
## Alternative implementations
@@ -98,12 +149,12 @@ I had several design goals which the existing crates didn't satisfy:
rigamarole. Support `serde` traits by default.
4. Well documented. Well tested. This varies by the crates.
All of that said, those other implementations might work best for you. Here are
the ones I know of today:
All of that said, those other rust implementations might work best for you.
Here are the ones I know of today:
- TODO: list crates
- TODO: list crates
- TODO: list crates
- [netloc](https://github.com/dgtony/netloc)
- [violin](https://crates.io/crates/violin)
- [vivaldi](https://crates.io/crates/vivaldi)
## Other Algorithms