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
use std::fmt;
use std::error::Error;

/// This type represents all possible errors that can occur when applying JSON patch
#[derive(Debug)]
pub enum PatchError {
    /// One of the paths in the patch is invalid
    InvalidPointer,

    /// 'test' operation failed
    TestFailed
}

impl Error for PatchError {
    fn description(&self) -> &str {
        use PatchError::*;
        match *self {
            InvalidPointer => "invalid pointer",
            TestFailed => "test failed"
        }
    }
}

impl fmt::Display for PatchError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(fmt)
    }
}


pub fn parse_index(str: &str, len: usize) -> Result<usize, PatchError> {
    // RFC 6901 prohibits leading zeroes in index
    if str.starts_with('0') && str.len() != 1 {
        return Err(PatchError::InvalidPointer)
    }
    match str.parse::<usize>() {
        Ok(idx) if idx < len => Ok(idx),
        Err(_) | Ok(_) => Err(PatchError::InvalidPointer)
    }
}

pub fn split_pointer(pointer: &str) -> Result<(&str, String), PatchError> {
    pointer.rfind('/')
        .ok_or(PatchError::InvalidPointer)
        .map(|idx| (&pointer[0..idx], pointer[idx + 1..].replace("~1", "/").replace("~0", "~")))
}