use serde_json::Map;
mod number;
mod serde;
pub use serde::Address;
pub use serde::from_str;
pub fn to_json_value(input: &str) -> serde_json::Value {
parse_struct(input)
}
struct Cursor<'a> {
ref_str: &'a str,
start: usize,
end: usize,
}
impl<'a> Cursor<'a> {
fn new(ref_str: &str) -> Cursor {
Cursor {
ref_str,
start: 0,
end: 0,
}
}
fn push(&mut self, idx: usize) {
if self.start == 0 {
self.start = idx;
}
self.end = idx + 1;
}
fn clear(&mut self) {
self.start = 0;
self.end = 0;
}
fn is_empty(&self) -> bool {
self.end == 0
}
fn get_str(&self) -> &'a str {
&self.ref_str[self.start..self.end]
}
}
fn is_array(input: &str) -> bool {
for char in input.chars() {
if char == ' ' || char == '\n' || char == '\r' {
continue;
}
if char == '[' {
return true;
}
return false;
}
false
}
fn is_field(input: &str) -> bool {
for char in input.chars() {
if char == ' ' || char == '\n' || char == '\r' {
continue;
}
if char == '[' || char == '{' {
return false;
}
return true;
}
false
}
pub(crate) fn parse_struct(input: &str) -> serde_json::Value {
if is_array(input) {
return serde_json::Value::Array(parse_array(input));
}
if is_field(input) {
return serde_json::Value::String(input.to_owned());
}
let mut self_map: Map<String, serde_json::Value> = Map::new();
let mut depth = 0;
let mut current_key = Cursor::new(input);
let mut current_child = Cursor::new(input);
let mut current_child_stack = 0;
let mut is_key = true;
for (idx, token) in input.char_indices() {
match token {
'{' => {
depth += 1;
if depth != 1 {
current_child.push(idx);
current_child_stack += 1;
}
}
'}' => {
depth -= 1;
if depth == 0 {
break;
} else {
current_child.push(idx);
current_child_stack -= 1;
if current_child_stack == 0 {
let current_child_str = current_child.get_str();
let current_key_str = current_key.get_str();
self_map
.insert(current_key_str.to_owned(), parse_struct(current_child_str));
current_key.clear();
current_child.clear();
is_key = true;
}
}
}
'[' => {
depth += 1;
current_child.push(idx);
current_child_stack += 1;
if depth == 1 {
is_key = false;
}
}
']' => {
depth -= 1;
current_child.push(idx);
current_child_stack -= 1;
if current_child_stack == 0 {
let current_key_str = current_key.get_str();
let current_child_str = current_child.get_str();
self_map.insert(
current_key_str.to_owned(),
serde_json::Value::Array(parse_array(current_child_str)),
);
current_key.clear();
current_child.clear();
}
}
':' => {
if depth == 1 {
is_key = false;
} else {
current_child.push(idx);
}
}
'\n' | ' ' | '\r' => {}
',' => {
if depth == 1 {
if !current_key.is_empty() {
let current_key_str = current_key.get_str();
let current_child_str = current_child.get_str();
self_map.insert(
current_key_str.to_owned(),
serde_json::Value::String(current_child_str.to_owned()),
);
}
current_key.clear();
current_child.clear();
is_key = true;
} else {
current_child.push(idx);
}
}
_ => {
if depth == 1 {
if is_key {
current_key.push(idx);
} else {
current_child.push(idx);
}
} else {
current_child.push(idx);
}
}
}
}
if !current_key.is_empty() {
self_map.insert(
current_key.get_str().to_owned(),
serde_json::Value::String(current_child.get_str().to_owned()),
);
}
serde_json::Value::Object(self_map)
}
fn parse_array(input: &str) -> Vec<serde_json::Value> {
let mut self_vec: Vec<serde_json::Value> = Vec::new();
let mut depth = 0;
let mut current_item = Cursor::new(input);
let mut current_item_stack = 0;
let mut current_object: Option<serde_json::Value> = None;
for (idx, token) in input.char_indices() {
match token {
'{' => {
depth += 1;
current_item.push(idx);
current_item_stack += 1;
}
'}' => {
depth -= 1;
current_item.push(idx);
current_item_stack -= 1;
if current_item_stack == 0 {
current_object = Some(parse_struct(current_item.get_str()));
}
}
'[' => {
depth += 1;
if depth != 1 {
current_item.push(idx);
current_item_stack += 1;
}
}
']' => {
depth -= 1;
if depth == 0 {
if let Some(obj) = current_object.take() {
self_vec.push(obj);
current_object = None;
} else {
self_vec.push(serde_json::Value::String(current_item.get_str().to_owned()));
current_item.clear();
current_item_stack = 0;
}
} else {
current_item.push(idx);
current_item_stack -= 1;
if current_item_stack == 0 {
current_object = Some(serde_json::Value::Array(parse_array(
current_item.get_str(),
)));
}
}
}
':' => {
current_item.push(idx);
}
'\n' | ' ' | '\r' => {}
',' => {
if depth == 1 {
if let Some(obj) = current_object.take() {
self_vec.push(obj);
current_object = None;
} else {
self_vec.push(serde_json::Value::String(current_item.get_str().to_owned()));
current_item.clear();
}
} else {
current_item.push(idx);
}
}
_ => {
current_item.push(idx);
}
}
}
self_vec
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_struct() {
let input = r#"
{
program_id: puzzle_arcade_ticket_v002.aleo,
function_name: mint,
arguments: [
aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl
]
}
"#;
let expect = r#"
{
"program_id": "puzzle_arcade_ticket_v002.aleo",
"function_name": "mint",
"arguments": [
"aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl"
]
}
"#;
let parsed_struct = parse_struct(input);
assert_eq!(
expect.trim().replace(' ', ""),
serde_json::to_string_pretty(&parsed_struct)
.unwrap()
.trim()
.replace(' ', "")
);
}
}