loro_common/
error.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use serde_columnar::ColumnarError;
use thiserror::Error;

use crate::{ContainerID, InternalString, PeerID, TreeID, ID};

pub type LoroResult<T> = Result<T, LoroError>;

#[derive(Error, Debug, PartialEq)]
pub enum LoroError {
    #[error("Context's client_id({found:?}) does not match Container's client_id({expected:?})")]
    UnmatchedContext { expected: PeerID, found: PeerID },
    #[error("Decode error: Version vector error. Please provide correct version.")]
    DecodeVersionVectorError,
    #[error("Decode error: ({0})")]
    DecodeError(Box<str>),
    #[error(
        // This should not happen after v1.0.0
        "Decode error: The data is either corrupted or originates from an older version that is incompatible due to a breaking change."
    )]
    DecodeDataCorruptionError,
    #[error("Decode error: Checksum mismatch. The data is corrupted.")]
    DecodeChecksumMismatchError,
    #[error("Decode error: Encoding version \"{0}\" is incompatible. Loro's encoding is backward compatible but not forward compatible. Please upgrade the version of Loro to support this version of the exported data.")]
    IncompatibleFutureEncodingError(usize),
    #[error("Js error ({0})")]
    JsError(Box<str>),
    #[error("Cannot get lock or the lock is poisoned")]
    LockError,
    #[error("Each AppState can only have one transaction at a time")]
    DuplicatedTransactionError,
    #[error("Cannot find ({0})")]
    NotFoundError(Box<str>),
    #[error("Transaction error ({0})")]
    TransactionError(Box<str>),
    #[error("Index out of bound. The given pos is {pos}, but the length is {len}. {info}")]
    OutOfBound {
        pos: usize,
        len: usize,
        info: Box<str>,
    },
    #[error("Every op id should be unique. ID {id} has been used. You should use a new PeerID to edit the content. ")]
    UsedOpID { id: ID },
    #[error("Concurrent ops with the same peer id is not allowed. PeerID: {peer}, LastCounter: {last_counter}, CurrentCounter: {current}")]
    ConcurrentOpsWithSamePeerID {
        peer: PeerID,
        last_counter: i32,
        current: i32,
    },
    #[error("Movable Tree Error: {0}")]
    TreeError(#[from] LoroTreeError),
    #[error("Invalid argument ({0})")]
    ArgErr(Box<str>),
    #[error("Auto commit has not started. The doc is readonly when detached and detached editing is not enabled.")]
    AutoCommitNotStarted,
    #[error("Style configuration missing for \"({0:?})\". Please provide the style configuration using `configTextStyle` on your Loro doc.")]
    StyleConfigMissing(InternalString),
    #[error("Unknown Error ({0})")]
    Unknown(Box<str>),
    #[error("The given ID ({0}) is not contained by the doc")]
    FrontiersNotFound(ID),
    #[error("Cannot import when the doc is in a transaction")]
    ImportWhenInTxn,
    #[error("The given method ({method}) is not allowed when the container is detached. You should insert the container to the doc first.")]
    MisuseDetachedContainer { method: &'static str },
    #[error("Not implemented: {0}")]
    NotImplemented(&'static str),
    #[error("Reattach a container that is already attached")]
    ReattachAttachedContainer,
    #[error("Edit is not allowed when the doc is in the detached mode.")]
    EditWhenDetached,
    #[error("The given ID ({0}) is not contained by the doc")]
    UndoInvalidIdSpan(ID),
    #[error("PeerID cannot be changed. Expected: {expected:?}, Actual: {actual:?}")]
    UndoWithDifferentPeerId { expected: PeerID, actual: PeerID },
    #[error("The input JSON schema is invalid")]
    InvalidJsonSchema,
    #[error("Cannot insert or delete utf-8 in the middle of the codepoint in Unicode")]
    UTF8InUnicodeCodePoint { pos: usize },
    #[error("Cannot insert or delete utf-16 in the middle of the codepoint in Unicode")]
    UTF16InUnicodeCodePoint { pos: usize },
    #[error("The end index cannot be less than the start index")]
    EndIndexLessThanStartIndex { start: usize, end: usize },
    #[error("Invalid root container name! Don't include '/' or '\\0'")]
    InvalidRootContainerName,
    #[error("Import Failed: The dependencies of the importing updates are not included in the shallow history of the doc.")]
    ImportUpdatesThatDependsOnOutdatedVersion,
    #[error(
        "You cannot switch a document to a version before the shallow history's start version."
    )]
    SwitchToVersionBeforeShallowRoot,
    #[error(
        "The container {container} is deleted. You cannot apply the op on a deleted container."
    )]
    ContainerDeleted { container: Box<ContainerID> },
    #[error("You cannot set the `PeerID` with `PeerID::MAX`, which is an internal specific value")]
    InvalidPeerID,
}

#[derive(Error, Debug, PartialEq)]
pub enum LoroTreeError {
    #[error("`Cycle move` occurs when moving tree nodes.")]
    CyclicMoveError,
    #[error("The provided parent id is invalid")]
    InvalidParent,
    #[error("The parent of tree node is not found {0:?}")]
    TreeNodeParentNotFound(TreeID),
    #[error("TreeID {0:?} doesn't exist")]
    TreeNodeNotExist(TreeID),
    #[error("The index({index}) should be <= the length of children ({len})")]
    IndexOutOfBound { len: usize, index: usize },
    #[error("Fractional index is not enabled, you should enable it first by `LoroTree::set_enable_fractional_index`")]
    FractionalIndexNotEnabled,
    #[error("TreeID {0:?} is deleted or does not exist")]
    TreeNodeDeletedOrNotExist(TreeID),
}

#[non_exhaustive]
#[derive(Error, Debug, PartialEq)]
pub enum LoroEncodeError {
    #[error("The frontiers are not found in this doc: {0}")]
    FrontiersNotFound(String),
    #[error("Shallow snapshot incompatible with old snapshot format. Use new snapshot format or avoid shallow snapshots for storage.")]
    ShallowSnapshotIncompatibleWithOldFormat,
    #[error("Cannot export shallow snapshot with unknown container type. Please upgrade the Loro version.")]
    UnknownContainer,
}

#[cfg(feature = "wasm")]
pub mod wasm {
    use wasm_bindgen::JsValue;

    use crate::{LoroEncodeError, LoroError};

    impl From<LoroError> for JsValue {
        fn from(value: LoroError) -> Self {
            JsValue::from_str(&value.to_string())
        }
    }

    impl From<LoroEncodeError> for JsValue {
        fn from(value: LoroEncodeError) -> Self {
            JsValue::from_str(&value.to_string())
        }
    }

    impl From<JsValue> for LoroError {
        fn from(v: JsValue) -> Self {
            Self::JsError(
                v.as_string()
                    .unwrap_or_else(|| "unknown error".to_owned())
                    .into_boxed_str(),
            )
        }
    }
}

impl From<ColumnarError> for LoroError {
    fn from(e: ColumnarError) -> Self {
        match e {
            ColumnarError::ColumnarDecodeError(_)
            | ColumnarError::RleEncodeError(_)
            | ColumnarError::RleDecodeError(_)
            | ColumnarError::OverflowError => {
                LoroError::DecodeError(format!("Failed to decode Columnar: {}", e).into_boxed_str())
            }
            e => LoroError::Unknown(e.to_string().into_boxed_str()),
        }
    }
}