solana-leader 0.4.0

solana leader library
Documentation
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JsonValue {
    Null,
    Bool(bool),
    Number(u64),
    String(String),
    Array(Vec<JsonValue>),
    Object(Vec<(String, JsonValue)>),
}

impl JsonValue {
    #[inline]
    pub fn as_u64(&self) -> Option<u64> {
        match self {
            Self::Number(value) => Some(*value),
            _ => None,
        }
    }

    #[inline]
    pub fn as_str(&self) -> Option<&str> {
        match self {
            Self::String(value) => Some(value),
            _ => None,
        }
    }

    #[inline]
    pub fn as_array(&self) -> Option<&[JsonValue]> {
        match self {
            Self::Array(values) => Some(values),
            _ => None,
        }
    }

    #[inline]
    pub fn as_object(&self) -> Option<&[(String, JsonValue)]> {
        match self {
            Self::Object(entries) => Some(entries),
            _ => None,
        }
    }

    #[inline]
    pub fn get(&self, key: &str) -> Option<&JsonValue> {
        self.as_object()?
            .iter()
            .find_map(|(entry_key, value)| (entry_key == key).then_some(value))
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JsonError {
    UnexpectedEnd,
    UnexpectedToken(u8),
    InvalidEscape,
    InvalidNumber,
    TrailingData,
}

impl fmt::Display for JsonError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::UnexpectedEnd => f.write_str("unexpected end of JSON"),
            Self::UnexpectedToken(token) => write!(f, "unexpected JSON token 0x{token:02x}"),
            Self::InvalidEscape => f.write_str("invalid JSON escape"),
            Self::InvalidNumber => f.write_str("invalid JSON number"),
            Self::TrailingData => f.write_str("trailing JSON data"),
        }
    }
}

impl std::error::Error for JsonError {}

pub fn parse(input: &str) -> Result<JsonValue, JsonError> {
    let mut parser = Parser::new(input.as_bytes());
    let value = parser.parse_value()?;
    parser.skip_ws();
    if parser.is_eof() {
        Ok(value)
    } else {
        Err(JsonError::TrailingData)
    }
}

struct Parser<'a> {
    input: &'a [u8],
    index: usize,
}

impl<'a> Parser<'a> {
    #[inline]
    fn new(input: &'a [u8]) -> Self {
        Self { input, index: 0 }
    }

    #[inline]
    fn is_eof(&self) -> bool {
        self.index >= self.input.len()
    }

    #[inline]
    fn peek(&self) -> Option<u8> {
        self.input.get(self.index).copied()
    }

    #[inline]
    fn bump(&mut self) -> Option<u8> {
        let value = self.peek()?;
        self.index += 1;
        Some(value)
    }

    fn skip_ws(&mut self) {
        while matches!(self.peek(), Some(b' ' | b'\n' | b'\r' | b'\t')) {
            self.index += 1;
        }
    }

    fn parse_value(&mut self) -> Result<JsonValue, JsonError> {
        self.skip_ws();
        match self.bump().ok_or(JsonError::UnexpectedEnd)? {
            b'n' => {
                self.expect_bytes(b"ull")?;
                Ok(JsonValue::Null)
            }
            b't' => {
                self.expect_bytes(b"rue")?;
                Ok(JsonValue::Bool(true))
            }
            b'f' => {
                self.expect_bytes(b"alse")?;
                Ok(JsonValue::Bool(false))
            }
            b'"' => Ok(JsonValue::String(self.parse_string()?)),
            b'[' => self.parse_array(),
            b'{' => self.parse_object(),
            byte @ b'0'..=b'9' => self.parse_number(byte),
            token => Err(JsonError::UnexpectedToken(token)),
        }
    }

    fn expect_bytes(&mut self, bytes: &[u8]) -> Result<(), JsonError> {
        for expected in bytes {
            let got = self.bump().ok_or(JsonError::UnexpectedEnd)?;
            if got != *expected {
                return Err(JsonError::UnexpectedToken(got));
            }
        }
        Ok(())
    }

    fn parse_string(&mut self) -> Result<String, JsonError> {
        let mut output = String::new();
        loop {
            match self.bump().ok_or(JsonError::UnexpectedEnd)? {
                b'"' => return Ok(output),
                b'\\' => {
                    let escaped = self.bump().ok_or(JsonError::UnexpectedEnd)?;
                    match escaped {
                        b'"' => output.push('"'),
                        b'\\' => output.push('\\'),
                        b'/' => output.push('/'),
                        b'b' => output.push('\u{0008}'),
                        b'f' => output.push('\u{000c}'),
                        b'n' => output.push('\n'),
                        b'r' => output.push('\r'),
                        b't' => output.push('\t'),
                        _ => return Err(JsonError::InvalidEscape),
                    }
                }
                byte if byte.is_ascii() => output.push(byte as char),
                token => return Err(JsonError::UnexpectedToken(token)),
            }
        }
    }

    fn parse_number(&mut self, first: u8) -> Result<JsonValue, JsonError> {
        let mut value = (first - b'0') as u64;
        while let Some(byte @ b'0'..=b'9') = self.peek() {
            self.index += 1;
            value = value
                .checked_mul(10)
                .and_then(|value| value.checked_add((byte - b'0') as u64))
                .ok_or(JsonError::InvalidNumber)?;
        }
        Ok(JsonValue::Number(value))
    }

    fn parse_array(&mut self) -> Result<JsonValue, JsonError> {
        let mut values = Vec::new();
        loop {
            self.skip_ws();
            if matches!(self.peek(), Some(b']')) {
                self.index += 1;
                return Ok(JsonValue::Array(values));
            }

            values.push(self.parse_value()?);
            self.skip_ws();
            match self.bump().ok_or(JsonError::UnexpectedEnd)? {
                b',' => {}
                b']' => return Ok(JsonValue::Array(values)),
                token => return Err(JsonError::UnexpectedToken(token)),
            }
        }
    }

    fn parse_object(&mut self) -> Result<JsonValue, JsonError> {
        let mut entries = Vec::new();
        loop {
            self.skip_ws();
            if matches!(self.peek(), Some(b'}')) {
                self.index += 1;
                return Ok(JsonValue::Object(entries));
            }

            if self.bump() != Some(b'"') {
                return Err(JsonError::UnexpectedToken(self.peek().unwrap_or_default()));
            }
            let key = self.parse_string()?;
            self.skip_ws();
            if self.bump() != Some(b':') {
                return Err(JsonError::UnexpectedToken(self.peek().unwrap_or_default()));
            }
            let value = self.parse_value()?;
            entries.push((key, value));

            self.skip_ws();
            match self.bump().ok_or(JsonError::UnexpectedEnd)? {
                b',' => {}
                b'}' => return Ok(JsonValue::Object(entries)),
                token => return Err(JsonError::UnexpectedToken(token)),
            }
        }
    }
}