使用Rust实现一个JSON解析器

摘要

使用Rust实现一个JSON解析器,这里不涉及编译原理相关知识,只需要使用几个栈就可以实现JSON格式的数据解析。

{
    "name": "John Doe",
    "age": 43,
    "address": {
        "street": "10 Downing Street",
        "city": "London"
    },
    "phones": [
        "+44 1234567",
        "+44 2345678"
    ]
}

上面的JSON数据对应Rust的HashMapVec嵌套的数据结构,被解析后显示效果如下图所示。
在这里插入图片描述

解析原理

先将原始的JSON数据转换成Token集合,Token集合中每一个Token都必须是合法,因此在解析Token的时候可以对JSON的基本数据类型进行校验。
JSON是一种类似树的数据结构,JSON的根节点可以是{},也可以是[],但是{}不可以直接包含[]{},必须是键值对的形式存在,而[]可以直接包含{}[],如[{},{},[]],这个是合法JSON结构,因此这里选用[]JSON的根节点。
利用栈来保存上下文状态。

 	let mut maps = Vec::new();
    let mut arrays = Vec::new();
    let mut keys = Vec::new();
    let mut parent_node = Vec::new();
    let mut symbols = Vec::new();
    let mut parse_state = Vec::new();
    let mut next_maybe_symbols = vec![SymbolEnum::BeginObject, SymbolEnum::BeginArray];

我们需要栈来保存上下文的状态,以此来判断该JSON数据是否是合法的JSON数据。栈保存了以下信息:

  • mapsarrays保存父节点。
  • keys保存当前的键,以确保键和值相互对应。
  • parent_node用来保存当前父节点是{}还是[]
  • symbols是一个符号栈,用来确定{}[]是否成对出现。
  • parse_state代表解析状态,代表当前是在解析key还是value,因为需要根据解析状态来确定下一个可能会遇见哪些Token,当解析状态为ParseKey时,那么下一个Token必须是String类型。
  • next_maybe_symbols 保存了下一步可能会遇见哪些符号,如{后面只能是String
 { -> string(key) }
 : -> bool number string null [ { (:只能出现在{}中)
 [ -> bool number string null [ { ]
 , -> string(key) (在{}中)
 , -> bool number string null [ { (在[]中)
 bool number string null -> , ] }
 } -> , } ]
 ] -> , } ]

代码实现

将JSON数据转换成Token集合

定义Token枚举,其中Token还包含Token所在JSON数据中行列位置,当解析出错时可以给出相应的提示。

#[derive(Clone, Debug, PartialEq)]
pub enum Token {
    //row col
    BeginObject(u64, u64), //{
    EndObject(u64, u64),   //}
    Colon(u64, u64),       //:
    BeginArray(u64, u64),  //[
    EndArray(u64, u64),    //]
    Comma(u64, u64),       //,
    Null(u64, u64),        //null
    Boolean(u64, u64, bool),
    String(u64, u64, String),
    Int64(u64, u64, i64),
    Float64(u64, u64, f64),
}

解析String类型

fn parse_string(row: &mut u64, col: &mut u64, chars: &mut Chars) -> Result<Token> {
    let r = *row;
    let c = *col;
    let mut token = String::new();
    let mut prev_ch = ' ';
    loop {
        if let Some(ch) = chars.next() {
            match ch {
                '"' => {
                    *col += 1;
                    if prev_ch == '\\' {
                        continue;
                    }else {
                        return Ok(Token::String(r, c, token));
                    }
                }
                '\n' => {
                    return Err(ParseError::InvalidToken(format!("JSON's Key and Value cannot contain '\\n', at {row}:{col}")))?;
                }
                '\t' => {
                    *col += 4;
                    token.push(ch);
                }

                _ => token.push(ch),
            }
            prev_ch = ch;
            *col += 1;
        } else {
            return Err(ParseError::InvalidToken(format!("String ends abnormally, at {row}:{col}.")))?;
        }
    }
}

解析Token集合

定义JSON值类型的枚举

#[derive(Debug)]
pub enum JsonValue {
    String(String),
    Int64(i64),
    Float64(f64),
    Boolean(bool),
    Object(HashMap<String, JsonValue>),
    Array(Vec<JsonValue>),
    Null,
}

定义Token对应的符号枚举

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SymbolEnum {
    /// {
    BeginObject,
    /// }
    EndObject,
    /// :
    Colon,
    /// [  
    BeginArray,
    /// ]
    EndArray,
    /// ,
    Comma,
    /// null
    Null,
    Boolean,
    String,
    Int64,
    Float64,
}

解析Token步骤如下

这里以解析到}为例。

  1. symbols栈弹出符号,判断是不是{
  2. }属于结束符,maps弹出一个HashMap,代表当前节点
  3. parent_node栈弹出
  4. 判断parent_node栈顶是Map类型还是Array类型,如果是Map类型,keys栈弹出一个key,并将第2步弹出的HashMap添加的到maps栈顶的HashMap
  5. 下一步可能遇见的符号,, ] }
    更多解析细节请查看完整代码。

实现Index、IndexMut特征

Rust支持运算符重载,JsonValue实现Index、IndexMux后可以使用[]来访问和修改JsonValue

let _=&json["data"]["list"][0]["url"];
json["data"]["list"][1]["url"]=JsonValue::String("http://www.abc123.com".to_string());

完整可运行代码

  1. Cargo.toml依赖
[package]
name = "json-parserlea"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.83"
thiserror = "1.0.61"
  1. 定义一个错误类型模块error.rs
use thiserror::Error;

#[derive(Error,Debug)]
pub enum  ParseError{
    #[error("parse int error")]
    ParseIntError(#[from] std::num::ParseIntError),
    #[error("parse float error")]
    ParseFloatError(#[from] std::num::ParseFloatError),
    #[error("`{0}`")]
    InvalidToken(String),
    #[error("`{0}`")]
    SymbolMismatch(String),
    #[error("`{0}`")]
    Unknown(String),
}
  1. 定义一个词法解析模块lex.rs
use std::{fmt::Display, str::Chars};
use anyhow::Result;

use crate::ParseError;

#[derive(Clone, Debug, PartialEq)]
pub enum Token {
    //row col
    BeginObject(u64, u64), //{
    EndObject(u64, u64),   //}
    Colon(u64, u64),       //:
    BeginArray(u64, u64),  //[
    EndArray(u64, u64),    //]
    Comma(u64, u64),       //,
    Null(u64, u64),        //null
    Boolean(u64, u64, bool),
    String(u64, u64, String),
    Int64(u64, u64, i64),
    Float64(u64, u64, f64),
}

impl Display for Token {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self {
            Token::BeginObject(_, _) => write!(f, "{{"),
            Token::EndObject(_, _) => write!(f, "}}"),
            Token::Colon(_, _) => write!(f, ":"),
            Token::BeginArray(_, _) => write!(f, "["),
            Token::EndArray(_, _) => write!(f, "]"),
            Token::Comma(_, _) => write!(f, ","),
            Token::Null(_, _) => write!(f, "null"),
            Token::Boolean(_, _, v) => write!(f, "{v}"),
            Token::String(_, _, v) => write!(f, "\"{v}\""),
            Token::Int64(_, _, v) => write!(f, "{v}"),
            Token::Float64(_, _, v) => write!(f, "{v}"),
        }
    }
}

pub fn parse<S: AsRef<str>>(s: S) -> Result<Vec<Token>> {
    let mut token_stream = vec![];
    let mut chars = s.as_ref().chars();
    let mut row = 1;
    let mut col = 1;
    while let Some(ch) = chars.next() {
        match ch {
            '{' => token_stream.push(Token::BeginObject(row, col)),
            '}' => token_stream.push(Token::EndObject(row, col)),
            '[' => token_stream.push(Token::BeginArray(row, col)),
            ']' => token_stream.push(Token::EndArray(row, col)),
            ':' => token_stream.push(Token::Colon(row, col)),
            ',' => token_stream.push(Token::Comma(row, col)),
            '\r' => continue,
            ' ' => {
                col += 1;
                continue;
            }
            '\t' => {
                col += 4;
                continue;
            }
            '\n' => {
                row += 1;
                col = 1;
                continue;
            }
            '"' => {
                let token = parse_string(&mut row, &mut col, &mut chars)?;
                token_stream.push(token);
            }
            '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
                let (token, next_token) = parse_number(&mut row, &mut col, ch, &mut chars)?;
                token_stream.push(token);
                token_stream.push(next_token);
            }
            't' | 'f' => {
                let token = parse_bool(&mut row, &mut col, ch, &mut chars)?;
                token_stream.push(token);
            }
            'n' => {
                let token = parse_null(&mut row, &mut col, &mut chars)?;
                token_stream.push(token);
            }
            _ => {
                return Err(ParseError::InvalidToken(format!("Invalid char '{ch}', at {row}:{col}.")))?;
            }
        }
        col += 1;
    }

    Ok(token_stream)
}

fn parse_string(row: &mut u64, col: &mut u64, chars: &mut Chars) -> Result<Token> {
    let r = *row;
    let c = *col;
    let mut token = String::new();
    let mut prev_ch = ' ';
    loop {
        if let Some(ch) = chars.next() {
            match ch {
                '"' => {
                    *col += 1;
                    if prev_ch == '\\' {
                        continue;
                    }else {
                        return Ok(Token::String(r, c, token));
                    }
                }
                '\n' => {
                    return Err(ParseError::InvalidToken(format!("JSON's Key and Value cannot contain '\\n', at {row}:{col}")))?;
                }
                '\t' => {
                    *col += 4;
                    token.push(ch);
                }

                _ => token.push(ch),
            }
            prev_ch = ch;
            *col += 1;
        } else {
            return Err(ParseError::InvalidToken(format!("String ends abnormally, at {row}:{col}.")))?;
        }
    }
}

fn parse_number(row: &mut u64, col: &mut u64, ch: char, chars: &mut Chars) -> Result<(Token, Token)> {
    let mut token = String::new();
    token.push(ch);
    let mut is_int = true;
    let mut next_token = Token::Comma(0, 0);
    let mut next_parse = false;
    loop {
        if let Some(ch) = chars.next() {
            match ch {
                '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
                    *col += 1;
                    token.push(ch);
                }
                '.' => {
                    *col += 1;
                    token.push(ch);
                    is_int = false;
                }
                ' ' | '\r' => {
                    *col += 1;
                    next_parse = true;
                    break;
                }
                '\t' => {
                    *col += 4;
                    next_parse = true;
                    break;
                }
                '\n' => {
                    *row += 1;
                    *col = 1;
                    next_parse = true;
                    break;
                }
                '}' => {
                    next_token = Token::EndObject(*row, *col);
                    *col += 1;
                    break;
                }
                ']' => {
                    next_token = Token::EndArray(*row, *col);
                    *col += 1;
                    break;
                }
                ',' => {
                    next_token = Token::Comma(*row, *col);
                    *col += 1;
                    break;
                }
                _ => {
                    return Err(ParseError::InvalidToken(format!("Invalid char '{ch}', at {row}:{col}.")))?;
                }
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Number ends abnormally, at {row}:{col}.")))?;
        }
    }

    if next_parse {
        loop {
            if let Some(ch) = chars.next() {
                match ch {
                    '}' => {
                        next_token = Token::EndObject(*row, *col);
                        *col += 1;
                        break;
                    }
                    ']' => {
                        next_token = Token::EndArray(*row, *col);
                        *col += 1;
                        break;
                    }
                    ',' => {
                        next_token = Token::Comma(*row, *col);
                        *col += 1;
                        break;
                    }
                    ' ' | '\r' => {
                        *col += 1;
                        continue;
                    }
                    '\t' => {
                        *col += 4;
                        continue;
                    }
                    '\n' => {
                        *row += 1;
                        *col = 1;
                        continue;
                    }
                    _ => {
                        return Err(ParseError::InvalidToken(format!("Invalid char '{ch}', at {row}:{col}.")))?;
                    }
                }
            } else {
                return Err(ParseError::InvalidToken(format!("Number ends abnormally, at {row}:{col}.")))?;
            }
        }
    }

    let token = if is_int {

        match token.parse::<i64>() {
            Ok(v)=>Token::Int64(*row, *col, v),
            Err(e)=>{
                return Err(ParseError::ParseIntError(e))?;
            }
        }
    } else {
        match token.parse::<f64>() {
            Ok(v)=>Token::Float64(*row, *col, v),
            Err(e)=>{
                return Err(ParseError::ParseFloatError(e))?;
            }
        }
        
    };
    Ok((token, next_token))
}

fn parse_bool(row: &mut u64, col: &mut u64, ch: char, chars: &mut Chars) -> Result<Token> {
    let r = *row;
    let c = *col;
    let token = if ch == 't' {
        if let Some(c) = chars.next() {
            if c != 'r' {
                return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
        }
        if let Some(c) = chars.next() {
            if c != 'u' {
                return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
        }
        if let Some(c) = chars.next() {
            if c != 'e' {
                return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
        }
        *col += 4;
        Ok(Token::Boolean(r, c, true))
    } else if ch == 'f' {
        if let Some(c) = chars.next() {
            if c != 'a' {
                return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
        }
        if let Some(c) = chars.next() {
            if c != 'l' {
                return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
        }
        if let Some(c) = chars.next() {
            if c != 's' {
                return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
        }
        if let Some(c) = chars.next() {
            if c != 'e' {
                return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
            }
        } else {
            return Err(ParseError::InvalidToken(format!("Boolean ends abnormally, at {row}:{col}.")))?;
        }
        *col += 5;
        Ok(Token::Boolean(r, c, false))
    } else {
        return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
    };

    token
}

fn parse_null(row: &mut u64, col: &mut u64, chars: &mut Chars) -> Result<Token> {
    if let Some(c) = chars.next() {
        if c != 'u' {
            return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
        }
    } else {
        return Err(ParseError::InvalidToken(format!("Null ends abnormally, at {row}:{col}.")))?;
    }
    if let Some(c) = chars.next() {
        if c != 'l' {
            return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
        }
    } else {
        return Err(ParseError::InvalidToken(format!("Null ends abnormally, at {row}:{col}.")))?;
    }
    if let Some(c) = chars.next() {
        if c != 'l' {
            return Err(ParseError::InvalidToken(format!("Invalid char '{c}', at {row}:{col}.")))?;
        }
    } else {
        return Err(ParseError::InvalidToken(format!("Null ends abnormally, at {row}:{col}.")))?;
    }
    let t = Token::Null(*row, *col);
    *col += 4;
    Ok(t)
}


  1. 解析Token的lib.rs
#![allow(dead_code)]
use anyhow::Result;
use std::collections::HashMap;
use std::ops::Index;
use std::ops::IndexMut;


mod error;
pub use error::ParseError;
mod lex;
pub use lex::parse;
pub use lex::Token;

#[derive(Debug)]
pub enum JsonValue {
    String(String),
    Int64(i64),
    Float64(f64),
    Boolean(bool),
    Object(HashMap<String, JsonValue>),
    Array(Vec<JsonValue>),
    Null,
}

#[derive(Debug)]
pub enum Json {
    Object(HashMap<String, JsonValue>),
    Array(Vec<JsonValue>),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParentNode {
    Map,
    Array,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
    ParseKey,
    ParseValue,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SymbolEnum {
    /// {
    BeginObject,
    /// }
    EndObject,
    /// :
    Colon,
    /// [  
    BeginArray,
    /// ]
    EndArray,
    /// ,
    Comma,
    /// null
    Null,
    Boolean,
    String,
    Int64,
    Float64,
}

impl Token {
    fn get_symbol(&self) -> SymbolEnum {
        match &self {
            Token::BeginObject(_, _) => SymbolEnum::BeginObject,
            Token::EndObject(_, _) => SymbolEnum::EndObject,
            Token::Colon(_, _) => SymbolEnum::Colon,
            Token::BeginArray(_, _) => SymbolEnum::BeginArray,
            Token::EndArray(_, _) => SymbolEnum::EndArray,
            Token::Comma(_, _) => SymbolEnum::Comma,
            Token::Null(_, _) => SymbolEnum::Null,
            Token::Boolean(_, _, _) => SymbolEnum::Boolean,
            Token::String(_, _, _) => SymbolEnum::String,
            Token::Int64(_, _, _) => SymbolEnum::Int64,
            Token::Float64(_, _, _) => SymbolEnum::Float64,
        }
    }
}

// { -> string(key) }
// : -> bool number string null [ { (:只能出现在{}中)
// [ -> bool number string null [ { ]
// , -> string(key) (在{}中)
// , -> bool number string null [ { (在[]中)
// bool number string null -> , ] }
// } -> , } ]
// ] -> , } ]

pub fn parse_json(token_stream: Vec<Token>) -> Result<Json> {
    let mut token_stream = token_stream.into_iter();

    let mut maps = Vec::new();
    let mut arrays = Vec::new();
    let mut keys = Vec::new();
    let mut parent_node = Vec::new();
    let mut symbols = Vec::new();
    let mut parse_state = Vec::new();
    let mut next_maybe_symbols = vec![SymbolEnum::BeginObject, SymbolEnum::BeginArray];

    parent_node.push(ParentNode::Array);
    arrays.push(Vec::new());

    while let Some(token) = token_stream.next() {
        let symbol = token.get_symbol();

        if !next_maybe_symbols.contains(&symbol) {
            let (row, col) = get_row_col(&token);
            let content = format!(
                "The following symbols may be required `{next_maybe_symbols:?}`,
             but provided is `{symbol:?}`, at {row}:{col}"
            );
            return Err(ParseError::SymbolMismatch(content))?;
        }

        next_maybe_symbols.clear();

        match token {
            Token::BeginObject(_, _) => {
                symbols.push(symbol);
                maps.push(HashMap::new());
                parent_node.push(ParentNode::Map);

                parse_state.push(State::ParseKey);
                next_maybe_symbols.push(SymbolEnum::String);
                next_maybe_symbols.push(SymbolEnum::EndObject);
            }
            Token::EndObject(row, col) => {
                if symbols.pop() != Some(SymbolEnum::BeginObject) {
                    let content = format!("Missing corresponding symbol, at {row}:{col}");
                    return Err(ParseError::SymbolMismatch(content))?;
                }

                let current_map = maps.pop().unwrap();
                let _ = parent_node.pop().unwrap();
                if current_map.is_empty() {
                    assert_eq!(parse_state.pop(), Some(State::ParseKey));
                }
                match parent_node.last().unwrap() {
                    ParentNode::Map => {
                        assert_eq!(parse_state.pop(), Some(State::ParseValue));
                        assert_eq!(parse_state.pop(), Some(State::ParseKey));

                        let k = keys.pop().unwrap();
                        maps.last_mut()
                            .unwrap()
                            .insert(k, JsonValue::Object(current_map));
                    }
                    ParentNode::Array => {
                        arrays
                            .last_mut()
                            .unwrap()
                            .push(JsonValue::Object(current_map));
                    }
                }

                next_maybe_symbols.push(SymbolEnum::Comma);
                next_maybe_symbols.push(SymbolEnum::EndArray);
                next_maybe_symbols.push(SymbolEnum::EndObject);
            }
            Token::BeginArray(_, _) => {
                symbols.push(symbol);
                arrays.push(Vec::new());
                parent_node.push(ParentNode::Array);

                next_maybe_symbols.push(SymbolEnum::String);
                next_maybe_symbols.push(SymbolEnum::Int64);
                next_maybe_symbols.push(SymbolEnum::Float64);
                next_maybe_symbols.push(SymbolEnum::Boolean);
                next_maybe_symbols.push(SymbolEnum::Null);
                next_maybe_symbols.push(SymbolEnum::BeginArray);
                next_maybe_symbols.push(SymbolEnum::EndArray);
                next_maybe_symbols.push(SymbolEnum::BeginObject);
            }
            Token::EndArray(row, col) => {
                if symbols.pop() != Some(SymbolEnum::BeginArray) {
                    let content = format!("Missing corresponding symbol, at {row}:{col}");
                    return Err(ParseError::SymbolMismatch(content))?;
                }

                let current_list = arrays.pop().unwrap();
                let _ = parent_node.pop().unwrap();

                match parent_node.last().unwrap() {
                    ParentNode::Map => {
                        assert_eq!(parse_state.pop(), Some(State::ParseValue));
                        assert_eq!(parse_state.pop(), Some(State::ParseKey));

                        let k = keys.pop().unwrap();
                        maps.last_mut()
                            .unwrap()
                            .insert(k, JsonValue::Array(current_list));
                    }
                    ParentNode::Array => {
                        arrays
                            .last_mut()
                            .unwrap()
                            .push(JsonValue::Array(current_list));
                    }
                }

                next_maybe_symbols.push(SymbolEnum::Comma);
                next_maybe_symbols.push(SymbolEnum::EndArray);
                next_maybe_symbols.push(SymbolEnum::EndObject);
            }
            Token::Comma(_, _) => match parent_node.last().unwrap() {
                ParentNode::Map => {
                    parse_state.push(State::ParseKey);
                    next_maybe_symbols.push(SymbolEnum::String);
                }
                ParentNode::Array => {
                    next_maybe_symbols.push(SymbolEnum::String);
                    next_maybe_symbols.push(SymbolEnum::Int64);
                    next_maybe_symbols.push(SymbolEnum::Float64);
                    next_maybe_symbols.push(SymbolEnum::Boolean);
                    next_maybe_symbols.push(SymbolEnum::Null);
                    next_maybe_symbols.push(SymbolEnum::BeginArray);
                    next_maybe_symbols.push(SymbolEnum::BeginObject);
                }
            },
            Token::String(_, _, string) => match parent_node.last().unwrap() {
                ParentNode::Map => match parse_state.last().unwrap() {
                    State::ParseKey => {
                        keys.push(string);
                        next_maybe_symbols.push(SymbolEnum::Colon);
                    }
                    State::ParseValue => {
                        let key = keys.pop().unwrap();
                        let value = JsonValue::String(string);
                        maps.last_mut().unwrap().insert(key, value);

                        assert_eq!(parse_state.pop(), Some(State::ParseValue));
                        assert_eq!(parse_state.pop(), Some(State::ParseKey));

                        next_maybe_symbols.push(SymbolEnum::Comma);
                        next_maybe_symbols.push(SymbolEnum::EndObject);
                    }
                },
                ParentNode::Array => {
                    let value = JsonValue::String(string);
                    arrays.last_mut().unwrap().push(value);

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndArray);
                }
            },
            Token::Colon(_, _) => {
                parse_state.push(State::ParseValue);

                next_maybe_symbols.push(SymbolEnum::String);
                next_maybe_symbols.push(SymbolEnum::Int64);
                next_maybe_symbols.push(SymbolEnum::Float64);
                next_maybe_symbols.push(SymbolEnum::Boolean);
                next_maybe_symbols.push(SymbolEnum::Null);
                next_maybe_symbols.push(SymbolEnum::BeginArray);
                next_maybe_symbols.push(SymbolEnum::BeginObject);
            }
            Token::Int64(_, _, int64) => match parent_node.last().unwrap() {
                ParentNode::Map => {
                    let key = keys.pop().unwrap();
                    let value = JsonValue::Int64(int64);
                    maps.last_mut().unwrap().insert(key, value);

                    assert_eq!(parse_state.pop(), Some(State::ParseValue));
                    assert_eq!(parse_state.pop(), Some(State::ParseKey));

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndObject);
                }
                ParentNode::Array => {
                    let value = JsonValue::Int64(int64);
                    arrays.last_mut().unwrap().push(value);

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndArray);
                }
            },
            Token::Float64(_, _, float64) => match parent_node.last().unwrap() {
                ParentNode::Map => {
                    let key = keys.pop().unwrap();
                    let value = JsonValue::Float64(float64);
                    maps.last_mut().unwrap().insert(key, value);

                    assert_eq!(parse_state.pop(), Some(State::ParseValue));
                    assert_eq!(parse_state.pop(), Some(State::ParseKey));

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndObject);
                }
                ParentNode::Array => {
                    let value = JsonValue::Float64(float64);
                    arrays.last_mut().unwrap().push(value);

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndArray);
                }
            },
            Token::Boolean(_, _, boolean) => match parent_node.last().unwrap() {
                ParentNode::Map => {
                    let key = keys.pop().unwrap();
                    let value = JsonValue::Boolean(boolean);
                    maps.last_mut().unwrap().insert(key, value);

                    assert_eq!(parse_state.pop(), Some(State::ParseValue));
                    assert_eq!(parse_state.pop(), Some(State::ParseKey));

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndObject);
                }
                ParentNode::Array => {
                    let value = JsonValue::Boolean(boolean);
                    arrays.last_mut().unwrap().push(value);

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndArray);
                }
            },
            Token::Null(_, _) => match parent_node.last().unwrap() {
                ParentNode::Map => {
                    let key = keys.pop().unwrap();
                    let value = JsonValue::Null;
                    maps.last_mut().unwrap().insert(key, value);

                    assert_eq!(parse_state.pop(), Some(State::ParseValue));
                    assert_eq!(parse_state.pop(), Some(State::ParseKey));

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndObject);
                }
                ParentNode::Array => {
                    let value = JsonValue::Null;
                    arrays.last_mut().unwrap().push(value);

                    next_maybe_symbols.push(SymbolEnum::Comma);
                    next_maybe_symbols.push(SymbolEnum::EndArray);
                }
            },
        }
    }

    let json = arrays.pop().unwrap().pop().unwrap();
    match json {
        JsonValue::Object(m) => Ok(Json::Object(m)),
        JsonValue::Array(l) => Ok(Json::Array(l)),
        _ => unreachable!(),
    }
}

#[inline]
fn get_row_col(token: &Token) -> (u64, u64) {
    match token {
        Token::BeginObject(r, c) => (*r, *c),
        Token::EndObject(r, c) => (*r, *c),
        Token::Colon(r, c) => (*r, *c),
        Token::BeginArray(r, c) => (*r, *c),
        Token::EndArray(r, c) => (*r, *c),
        Token::Comma(r, c) => (*r, *c),
        Token::Null(r, c) => (*r, *c),
        Token::Boolean(r, c, _) => (*r, *c),
        Token::String(r, c, _) => (*r, *c),
        Token::Int64(r, c, _) => (*r, *c),
        Token::Float64(r, c, _) => (*r, *c),
    }
}

impl<'a> Index<&'a str> for Json {
    type Output = JsonValue;
    fn index(&self, index: &str) -> &Self::Output {
        match self {
            Json::Array(_) => {
                panic!("This operation is not supported.")
            }
            Json::Object(value) => &value[index],
        }
    }
}

impl Index<usize> for Json {
    type Output = JsonValue;
    fn index(&self, index: usize) -> &Self::Output {
        match self {
            Json::Array(value) => &value[index],
            Json::Object(_) => {
                panic!("This operation is not supported.")
            }
        }
    }
}

impl<'a> Index<&'a str> for JsonValue {
    type Output = JsonValue;
    fn index(&self, index: &str) -> &Self::Output {
        match self {
            JsonValue::Object(value) => &value[index],
            _ => {
                panic!("This operation is not supported.")
            }
        }
    }
}

impl Index<usize> for JsonValue {
    type Output = JsonValue;
    fn index(&self, index: usize) -> &Self::Output {
        match self {
            JsonValue::Array(value) => &value[index],
            _ => {
                panic!("This operation is not supported.")
            }
        }
    }
}



impl<'a> IndexMut<&'a str> for Json {
    
    fn index_mut(&mut self, index: &str) -> &mut Self::Output {
        match self {
            Json::Array(_) => {
                panic!("This operation is not supported.")
            }
            Json::Object(value) => value.get_mut(index).expect("no entry found for key"),
        }
    }
}

impl IndexMut<usize> for Json {
    
    fn index_mut(&mut self,  index: usize) -> &mut Self::Output {
        match self {
            Json::Array(value) => value.get_mut(index).expect("Index out of bounds."),
            Json::Object(_) => {
                panic!("This operation is not supported.")
            }
        }
    }
}


impl<'a> IndexMut<&'a str> for JsonValue {
    
    fn index_mut(&mut self, index: &str) -> &mut Self::Output {
        match self {
            JsonValue::Object(value) => value.get_mut(index).expect("no entry found for key"),
            _ => {
                panic!("This operation is not supported.")
            }
        }
    }
}

impl IndexMut<usize> for JsonValue {
    
    fn index_mut(&mut self,  index: usize) -> &mut Self::Output {
        match self {
            JsonValue::Array(value) => value.get_mut(index).expect("Index out of bounds."),
            _ => {
                panic!("This operation is not supported.")
            }
        }
    }
}

效果演示

JSON文件

use json_parserlea::{parse, Json, JsonValue};
use std::fs;

fn main() {
    let json = fs::read_to_string("./jsons/images.json").unwrap();

    let tokens = parse(json.as_str()).unwrap();
    let mut json = json_parserlea::parse_json(tokens).unwrap();
    println!("{:#?}", json);

    json["data"]["list"][1]["url"]=JsonValue::String("http://www.abc123.com".to_string());
    let j=&json["data"]["list"][0]["url"];
    println!("{:#?}",j);
    
    match json {
        Json::Array(_) => unreachable!(),
        Json::Object(map) => match &map["data"] {
            JsonValue::Object(map) => match &map["list"] {
                JsonValue::Array(list) => {
                    let urls = list
                        .iter()
                        .map(|value| match value {
                            JsonValue::Object(obj) => &obj["url"],
                            _ => unreachable!(),
                        })
                        .map(|value| match value {
                            JsonValue::String(v) => v,
                            _ => unreachable!(),
                        })
                        .collect::<Vec<&String>>();
                    println!("{:#?}", urls);
                }
                _ => unreachable!(),
            },
            _ => unreachable!(),
        },
    }
}

解析结果

  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值