Skip to main content

DataDoc

Struct DataDoc 

Source
pub struct DataDoc { /* private fields */ }
Expand description

A replicated document.

Holds named collections (map, list, text, counter). Concurrent edits from any replica merge deterministically, and applying the same change twice is a no-op, which is what lets this layer ride a transport ladder that only promises at-least-once, unordered delivery.

Implementations§

Source§

impl DataDoc

Source

pub fn new() -> Self

Create an empty document.

Examples found in repository?
examples/offline_merge.rs (line 31)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn is_poisoned(&self) -> bool

Whether this handle has been poisoned by a decode failure.

A poisoned handle never recovers. The owner drops it and re-opens the document from storage, which is a decision only the owner can make.

Source

pub fn import(&mut self, bytes: &[u8]) -> DataResult<ImportOutcome>

Apply an encoded snapshot or delta.

Every blob reaching this method comes back out of a sealed protocol-state record, so an AEAD tag has already established that these are bytes this SDK wrote and nobody altered. That is the real containment for the engine’s known import-panic classes, and the reason no code path may ever feed unverified bytes here: the catch_unwind below is a second line, which poisons this handle when it catches, and under panic = "abort" it does not exist at all. It wraps the engine’s apply step only. The header decode just above it, like DataDoc::inspect, runs outside it, so a panic there unwinds to the caller and leaves this handle live.

Returns whether the blob applied or is parked behind a missing predecessor. Callers that can destroy history (compaction, log truncation) must branch on it: see ImportOutcome.

Examples found in repository?
examples/offline_merge.rs (line 37)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn inspect(&self, bytes: &[u8]) -> DataResult<BlobMeta>

Judge a blob against this document without letting the engine touch it.

The whole point is that this runs first. Header decoding with the checksum on is the cheap part; the verdicts it produces are what let a caller refuse the two blob shapes that are known to end a process rather than return an error.

Source

pub fn import_remote(&mut self, bytes: &[u8]) -> DataResult<RemoteImport>

Apply a blob that arrived from a peer.

DataDoc::import exists for bytes that came back out of a sealed record, where an AEAD tag has already established that this SDK wrote them. Nothing of the sort is true here: a peer is authenticated, which says who sent the bytes and nothing at all about their shape. So this path re-judges every blob with DataDoc::inspect and declines the two shapes the engine is known to panic on, rather than relying on the unwinding catch in DataDoc::import: it covers the apply step only, poisons this handle when it fires, and does not exist in a host built with panic = "abort".

Refusing is not a failure: a duplicate is the ladder keeping its at-least-once promise, and a trimmed-history gap in a run of changes is answered by asking for a snapshot. Both are recorded outcomes, not errors. The same refusal on a snapshot is the exception: it means the replicas have diverged past anything a frame can carry, and the caller has nothing left to ask for.

Source

pub fn export_since(&self, from: &VersionToken) -> DataResult<CatchUp>

Encode what a replica at from is missing.

from is a token that replica produced with DataDoc::version. A token this document cannot decode is treated as corrupt rather than as “send everything”: on the sync path the token is remote input, and answering a malformed one with the whole document would make a garbled byte an amplification lever.

Source

pub fn mark_persisted(&mut self)

Declare everything currently in the document as already persisted.

Called after loading a snapshot and its delta log, so the next commit exports only genuinely new changes instead of re-emitting the history that was just read off disk.

Source

pub fn commit(&mut self) -> DataResult<Option<Delta>>

Commit pending edits and return the change they produced.

Ok(None) means nothing had changed. The returned delta is exactly the bytes needed to bring a replica at the previous version up to the current one, which is what the delta log stores and what F3 will send.

Examples found in repository?
examples/offline_merge.rs (line 34)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn rewind_last_commit(&mut self)

Undo the bookkeeping of the last commit, so its change is handed out again by the next one.

For the caller whose write failed. The document keeps the edits (they happened, and the application is looking at them); what is undone is only the claim that someone has taken responsibility for persisting them. Without this a failed write loses the change at the next restart, silently, which is the worst shape a storage error can take.

Safe to call spuriously: re-exporting a delta that did reach storage costs one duplicate record, and duplicates are free by construction.

Source

pub fn version(&self) -> VersionToken

The current version of the document.

Source

pub fn export_compacted(&self) -> DataResult<Vec<u8>>

Encode the document compactly, discarding history.

This is what a document record stores: a 10,000 operation document compacts to under a kilobyte here, against tens of kilobytes of full history, which is what keeps a document inside one sealed record and a catch-up inside one message.

Source

pub fn export_raw(&self) -> DataResult<Vec<u8>>

Encode the document with its full history.

Part of the escape hatch: an application can always take this and leave. Prefer DataDoc::export_compacted for storage and transfer.

Source

pub fn export_json(&self) -> DataResult<String>

The document’s current state as plain JSON.

The second half of the escape hatch, and the one that does not require the reader to know anything about this SDK at all.

Examples found in repository?
examples/offline_merge.rs (line 39)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn measure(&mut self) -> DataResult<usize>

Measure the compacted encoding and refresh the size bookkeeping.

Source

pub fn check_size(&mut self) -> DataResult<(SizeVerdict, Option<usize>)>

Check the document against the size cap, measuring only when the running estimate says a breach is possible.

Returns the verdict and, when a measurement happened, the true size.

Source

pub fn stats(&mut self) -> DataResult<DocStats>

Statistics for compaction and cap decisions.

Source

pub fn commits_since_compaction(&self) -> u32

Commits recorded since the last compaction.

Source

pub fn mark_compacted(&mut self, compacted_bytes: usize)

Reset the compaction counter, after the owner has written a fresh compacted record and dropped the folded delta records.

Source

pub fn restore_bookkeeping( &mut self, compacted_bytes: usize, log_bytes: usize, commits: u32, )

Adopt the bookkeeping of a document just loaded from storage.

Without this a reopened document starts as though it were empty, and the cheap size estimate then under-reports by the entire size of what was loaded: a document already near the cap would look far from it and sail past without ever triggering a real measurement. Passing the record sizes in keeps the estimate an over-estimate, which is the property the whole check depends on.

compacted_bytes is the size of the stored snapshot and log_bytes the total size of the delta records replayed on top of it.

Source

pub fn map_set( &mut self, collection: &str, key: &str, value: DataValue, ) -> DataResult<()>

Set a key in a map collection.

Examples found in repository?
examples/offline_merge.rs (line 32)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn map_delete(&mut self, collection: &str, key: &str) -> DataResult<()>

Remove a key from a map collection.

Source

pub fn map_get( &self, collection: &str, key: &str, ) -> DataResult<Option<DataValue>>

Read a key from a map collection.

Source

pub fn list_push( &mut self, collection: &str, value: DataValue, ) -> DataResult<()>

Append to a list collection.

Examples found in repository?
examples/offline_merge.rs (line 33)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn list_insert( &mut self, collection: &str, index: usize, value: DataValue, ) -> DataResult<()>

Insert into a list collection at index.

Source

pub fn list_delete( &mut self, collection: &str, index: usize, count: usize, ) -> DataResult<()>

Delete count entries from a list collection at index.

Source

pub fn list_len(&self, collection: &str) -> DataResult<usize>

Number of entries in a list collection.

Examples found in repository?
examples/offline_merge.rs (line 84)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn text_insert( &mut self, collection: &str, position: usize, text: &str, ) -> DataResult<()>

Insert text into a text collection at a character position.

Examples found in repository?
examples/offline_merge.rs (line 45)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn text_delete( &mut self, collection: &str, position: usize, count: usize, ) -> DataResult<()>

Delete count characters from a text collection at position.

Source

pub fn text_value(&self, collection: &str) -> DataResult<String>

The current contents of a text collection.

Examples found in repository?
examples/offline_merge.rs (line 85)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn counter_increment( &mut self, collection: &str, amount: f64, ) -> DataResult<()>

Add to a counter collection. Negative values subtract.

Examples found in repository?
examples/offline_merge.rs (line 46)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}
Source

pub fn counter_value(&self, collection: &str) -> DataResult<f64>

The current value of a counter collection.

Examples found in repository?
examples/offline_merge.rs (line 86)
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30    // One shared starting point: Ada writes, and Bo receives that change.
31    let mut ada = DataDoc::new();
32    ada.map_set("meta", "title", text("Coast road"))?;
33    ada.list_push("packing", text("water"))?;
34    let shared = ada.commit()?.expect("a change to share");
35
36    let mut bo = DataDoc::new();
37    bo.import(&shared.bytes)?;
38
39    println!("both start at: {}", bo.export_json()?);
40
41    // The link goes away here. Neither side can see the other's edits, and
42    // neither side blocks on that.
43    ada.map_set("meta", "title", text("Coast road, Friday"))?;
44    ada.list_push("packing", text("map"))?;
45    ada.text_insert("notes", 0, "leave at six")?;
46    ada.counter_increment("edits", 1.0)?;
47    let from_ada = ada.commit()?.expect("Ada's offline work");
48
49    bo.map_set("meta", "title", text("Coast road, Saturday"))?;
50    bo.list_push("packing", text("torch"))?;
51    bo.text_insert("notes", 0, "bring the tent, ")?;
52    bo.counter_increment("edits", 1.0)?;
53    let from_bo = bo.commit()?.expect("Bo's offline work");
54
55    println!("apart, Ada has: {}", ada.export_json()?);
56    println!("apart, Bo has:  {}", bo.export_json()?);
57
58    // The link comes back. Each side imports what the other committed. Order
59    // does not matter and neither does arriving twice: importing the same
60    // bytes again is a no-op, which is why at-least-once delivery is enough.
61    ada.import(&from_bo.bytes)?;
62    bo.import(&from_ada.bytes)?;
63    bo.import(&from_ada.bytes)?;
64
65    let ada_state = ada.export_json()?;
66    let bo_state = bo.export_json()?;
67
68    println!("together, Ada: {ada_state}");
69    println!("together, Bo:  {bo_state}");
70    println!("identical:     {}", ada_state == bo_state);
71
72    // Read that state against the four collection types:
73    //
74    // - `meta.title` is a map key two people wrote. One value wins, both
75    //   replicas pick the same one, and neither ends up holding half of each.
76    //   That is the reason to put independently editable fields in separate
77    //   keys rather than in one JSON blob.
78    // - `packing` kept every insertion. A list loses nothing to a concurrent
79    //   push.
80    // - `notes` merged at character level, so both sentences survive.
81    // - `edits` is 2. Two offline increments of 1 add up rather than
82    //   overwriting each other, which is what makes a counter a counter and
83    //   not an integer in a map.
84    println!("packing:       {} entries", ada.list_len("packing")?);
85    println!("notes:         {:?}", ada.text_value("notes")?);
86    println!("edits:         {}", ada.counter_value("edits")?);
87
88    Ok(())
89}

Trait Implementations§

Source§

impl Debug for DataDoc

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for DataDoc

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Paint for T
where T: ?Sized,

Source§

fn fg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the foreground set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like red() and green(), which have the same functionality but are pithier.

§Example

Set foreground color to white using fg():

use yansi::{Paint, Color};

painted.fg(Color::White);

Set foreground color to white using white().

use yansi::Paint;

painted.white();
Source§

fn primary(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Primary].

§Example
println!("{}", value.primary());
Source§

fn fixed(&self, color: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Fixed].

§Example
println!("{}", value.fixed(color));
Source§

fn rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Rgb].

§Example
println!("{}", value.rgb(r, g, b));
Source§

fn black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Black].

§Example
println!("{}", value.black());
Source§

fn red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Red].

§Example
println!("{}", value.red());
Source§

fn green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Green].

§Example
println!("{}", value.green());
Source§

fn yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Yellow].

§Example
println!("{}", value.yellow());
Source§

fn blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Blue].

§Example
println!("{}", value.blue());
Source§

fn magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Magenta].

§Example
println!("{}", value.magenta());
Source§

fn cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Cyan].

§Example
println!("{}", value.cyan());
Source§

fn white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: White].

§Example
println!("{}", value.white());
Source§

fn bright_black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlack].

§Example
println!("{}", value.bright_black());
Source§

fn bright_red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightRed].

§Example
println!("{}", value.bright_red());
Source§

fn bright_green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightGreen].

§Example
println!("{}", value.bright_green());
Source§

fn bright_yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightYellow].

§Example
println!("{}", value.bright_yellow());
Source§

fn bright_blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlue].

§Example
println!("{}", value.bright_blue());
Source§

fn bright_magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.bright_magenta());
Source§

fn bright_cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightCyan].

§Example
println!("{}", value.bright_cyan());
Source§

fn bright_white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightWhite].

§Example
println!("{}", value.bright_white());
Source§

fn bg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the background set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like on_red() and on_green(), which have the same functionality but are pithier.

§Example

Set background color to red using fg():

use yansi::{Paint, Color};

painted.bg(Color::Red);

Set background color to red using on_red().

use yansi::Paint;

painted.on_red();
Source§

fn on_primary(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Primary].

§Example
println!("{}", value.on_primary());
Source§

fn on_fixed(&self, color: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Fixed].

§Example
println!("{}", value.on_fixed(color));
Source§

fn on_rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Rgb].

§Example
println!("{}", value.on_rgb(r, g, b));
Source§

fn on_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Black].

§Example
println!("{}", value.on_black());
Source§

fn on_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Red].

§Example
println!("{}", value.on_red());
Source§

fn on_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Green].

§Example
println!("{}", value.on_green());
Source§

fn on_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Yellow].

§Example
println!("{}", value.on_yellow());
Source§

fn on_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Blue].

§Example
println!("{}", value.on_blue());
Source§

fn on_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Magenta].

§Example
println!("{}", value.on_magenta());
Source§

fn on_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Cyan].

§Example
println!("{}", value.on_cyan());
Source§

fn on_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: White].

§Example
println!("{}", value.on_white());
Source§

fn on_bright_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlack].

§Example
println!("{}", value.on_bright_black());
Source§

fn on_bright_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightRed].

§Example
println!("{}", value.on_bright_red());
Source§

fn on_bright_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightGreen].

§Example
println!("{}", value.on_bright_green());
Source§

fn on_bright_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightYellow].

§Example
println!("{}", value.on_bright_yellow());
Source§

fn on_bright_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlue].

§Example
println!("{}", value.on_bright_blue());
Source§

fn on_bright_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.on_bright_magenta());
Source§

fn on_bright_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightCyan].

§Example
println!("{}", value.on_bright_cyan());
Source§

fn on_bright_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightWhite].

§Example
println!("{}", value.on_bright_white());
Source§

fn attr(&self, value: Attribute) -> Painted<&T>

Enables the styling Attribute value.

This method should be used rarely. Instead, prefer to use attribute-specific builder methods like bold() and underline(), which have the same functionality but are pithier.

§Example

Make text bold using attr():

use yansi::{Paint, Attribute};

painted.attr(Attribute::Bold);

Make text bold using using bold().

use yansi::Paint;

painted.bold();
Source§

fn bold(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Bold].

§Example
println!("{}", value.bold());
Source§

fn dim(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Dim].

§Example
println!("{}", value.dim());
Source§

fn italic(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Italic].

§Example
println!("{}", value.italic());
Source§

fn underline(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Underline].

§Example
println!("{}", value.underline());

Returns self with the attr() set to [Attribute :: Blink].

§Example
println!("{}", value.blink());

Returns self with the attr() set to [Attribute :: RapidBlink].

§Example
println!("{}", value.rapid_blink());
Source§

fn invert(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Invert].

§Example
println!("{}", value.invert());
Source§

fn conceal(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Conceal].

§Example
println!("{}", value.conceal());
Source§

fn strike(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Strike].

§Example
println!("{}", value.strike());
Source§

fn quirk(&self, value: Quirk) -> Painted<&T>

Enables the yansi Quirk value.

This method should be used rarely. Instead, prefer to use quirk-specific builder methods like mask() and wrap(), which have the same functionality but are pithier.

§Example

Enable wrapping using .quirk():

use yansi::{Paint, Quirk};

painted.quirk(Quirk::Wrap);

Enable wrapping using wrap().

use yansi::Paint;

painted.wrap();
Source§

fn mask(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Mask].

§Example
println!("{}", value.mask());
Source§

fn wrap(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Wrap].

§Example
println!("{}", value.wrap());
Source§

fn linger(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Linger].

§Example
println!("{}", value.linger());
Source§

fn clear(&self) -> Painted<&T>

👎Deprecated since 1.0.1:

renamed to resetting() due to conflicts with Vec::clear(). The clear() method will be removed in a future release.

Returns self with the quirk() set to [Quirk :: Clear].

§Example
println!("{}", value.clear());
Source§

fn resetting(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Resetting].

§Example
println!("{}", value.resetting());
Source§

fn bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Bright].

§Example
println!("{}", value.bright());
Source§

fn on_bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: OnBright].

§Example
println!("{}", value.on_bright());
Source§

fn whenever(&self, value: Condition) -> Painted<&T>

Conditionally enable styling based on whether the Condition value applies. Replaces any previous condition.

See the crate level docs for more details.

§Example

Enable styling painted only when both stdout and stderr are TTYs:

use yansi::{Paint, Condition};

painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
Source§

fn new(self) -> Painted<Self>
where Self: Sized,

Create a new Painted with a default Style. Read more
Source§

fn paint<S>(&self, style: S) -> Painted<&Self>
where S: Into<Style>,

Apply a style wholesale to self. Any previous style is replaced. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ZeroElement for T
where T: Default,