use super::types::*;
/// Maximum length for a single JSON string value (1 MB).
const MAX_STRING_LEN: usize = 1_000_000;
/// Maximum number of items in a JSON array.
const MAX_ARRAY_ITEMS: usize = 10_000;
pub(super) fn json_escape(s: &str) -> String {
let mut out = String::from("\"");
for ch in s.chars() {
match ch {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
c if (c as u32) < 0x20 => {
out.push_str(&format!("\\u{:04x}", c as u32));
}
c => out.push(c),
}
}
out.push('"');
out
}
/// Find a top-level JSON key (depth 1) and return its byte offset.
/// Skips keys nested inside arrays or sub-objects by tracking
/// brace/bracket nesting while being aware of JSON strings.
pub(super) fn find_toplevel_key(json: &str, key: &str) -> Option<usize> {
let needle = format!("\"{}\":", key);
let bytes = json.as_bytes();
let mut depth = 0usize;
let mut i = 0;
while i < bytes.len() {
let b = bytes[i];
if b == b'"' {
// Skip over the entire JSON string (key or value).
// Record the start position โ we may need to match here.
let start = i;
i += 1; // skip opening quote
while i < bytes.len() {
if bytes[i] == b'\\' {
i += 2; // skip escaped char
} else if bytes[i] == b'"' {
i += 1; // skip closing quote
break;
} else {
i += 1;
}
}
// At depth 1, check if this position is our needle.
if depth == 1 && json[start..].starts_with(&needle) {
return Some(start);
}
continue;
}
match b {
b'{' | b'[' => depth += 1,
b'}' | b']' => depth = depth.saturating_sub(1),
_ => {}
}
i += 1;
}
None
}
pub(super) fn extract_json_string(json: &str, key: &str) -> String {
let needle = format!("\"{}\":", key);
if let Some(pos) = find_toplevel_key(json, key) {
let after = &json[pos + needle.len()..];
let after = after.trim_start();
if after.starts_with('"') {
let inner = &after[1..];
let mut result = String::new();
let mut chars = inner.chars();
while let Some(ch) = chars.next() {
if ch == '"' {
break;
}
if ch == '\\' {
match chars.next() {
Some('n') => result.push('\n'),
Some('r') => result.push('\r'),
Some('t') => result.push('\t'),
Some('"') => result.push('"'),
Some('\\') => result.push('\\'),
Some(c) => {
result.push('\\');
result.push(c);
}
None => break,
}
} else {
result.push(ch);
}
if result.len() > MAX_STRING_LEN {
return String::new();
}
}
return result;
}
}
String::new()
}
pub(super) fn extract_json_bool(json: &str, key: &str) -> bool {
let needle = format!("\"{}\":", key);
if let Some(pos) = find_toplevel_key(json, key) {
let after = &json[pos + needle.len()..];
let after = after.trim_start();
return after.starts_with("true");
}
false
}
pub(super) fn extract_json_array_strings(json: &str, key: &str) -> Vec<String> {
let needle = format!("\"{}\":", key);
let mut results = Vec::new();
if let Some(pos) = find_toplevel_key(json, key) {
let after = &json[pos + needle.len()..];
let after = after.trim_start();
if after.starts_with('[') {
let bracket_end = find_matching_bracket(after);
let inner = &after[1..bracket_end];
for item in inner.split(',') {
if results.len() >= MAX_ARRAY_ITEMS {
break;
}
let item = item.trim();
if item.starts_with('"') && item.ends_with('"') {
let value = &item[1..item.len() - 1];
if value.len() > MAX_STRING_LEN {
continue;
}
results.push(value.to_string());
}
}
}
}
results
}
pub(super) fn find_matching_bracket(s: &str) -> usize {
let mut depth = 0;
for (i, ch) in s.chars().enumerate() {
match ch {
'[' => depth += 1,
']' => {
depth -= 1;
if depth == 0 {
return i;
}
}
_ => {}
}
}
s.len()
}
pub(super) fn format_publish_json(def: &PublishedDefinition) -> String {
let deps: Vec<String> = def
.dependencies
.iter()
.map(|h| format!("\"{}\"", h))
.collect();
let params: Vec<String> = def
.params
.iter()
.map(|(n, t)| {
format!(
"{{\"name\":{},\"type\":{}}}",
json_escape(n),
json_escape(t)
)
})
.collect();
let requires: Vec<String> = def.requires.iter().map(|r| json_escape(r)).collect();
let ensures: Vec<String> = def.ensures.iter().map(|e| json_escape(e)).collect();
let tags: Vec<String> = def.tags.iter().map(|t| json_escape(t)).collect();
format!(
"{{\"hash\":\"{}\",\"source\":{},\"module\":{},\"is_pub\":{},\"params\":[{}],\"return_ty\":{},\"dependencies\":[{}],\"requires\":[{}],\"ensures\":[{}],\"name\":{},\"tags\":[{}],\"verified\":{},\"verification_cert\":{}}}",
def.hash,
json_escape(&def.source),
json_escape(&def.module),
def.is_pub,
params.join(","),
def.return_ty.as_ref().map(|t| json_escape(t)).unwrap_or_else(|| "null".to_string()),
deps.join(","),
requires.join(","),
ensures.join(","),
def.name.as_ref().map(|n| json_escape(n)).unwrap_or_else(|| "null".to_string()),
tags.join(","),
def.verified,
def.verification_cert.as_ref().map(|c| json_escape(c)).unwrap_or_else(|| "null".to_string()),
)
}
#[cfg(test)]
pub(super) fn parse_publish_body(body: &str) -> Result<PublishedDefinition, String> {
let hash = extract_json_string(body, "hash");
if hash.is_empty() {
return Err("missing 'hash' field".to_string());
}
if hash.len() != 64 || !hash.chars().all(|c| c.is_ascii_hexdigit()) {
return Err("invalid hash format (expected 64 hex chars)".to_string());
}
let source = extract_json_string(body, "source");
if source.is_empty() {
return Err("missing 'source' field".to_string());
}
let module = extract_json_string(body, "module");
let is_pub = extract_json_bool(body, "is_pub");
let return_ty = {
let rt = extract_json_string(body, "return_ty");
if rt.is_empty() {
None
} else {
Some(rt)
}
};
let params = extract_params_array(body);
let dependencies = extract_json_array_strings(body, "dependencies");
let requires = extract_json_array_strings(body, "requires");
let ensures = extract_json_array_strings(body, "ensures");
let tags = extract_json_array_strings(body, "tags");
let name = {
let n = extract_json_string(body, "name");
if n.is_empty() {
None
} else {
Some(n)
}
};
let verified = extract_json_bool(body, "verified");
let verification_cert = {
let vc = extract_json_string(body, "verification_cert");
if vc.is_empty() {
None
} else {
Some(vc)
}
};
Ok(PublishedDefinition {
hash,
source,
module,
is_pub,
params,
return_ty,
dependencies,
requires,
ensures,
name,
tags,
verified,
verification_cert,
})
}
pub(super) fn extract_params_array(json: &str) -> Vec<(String, String)> {
let needle = "\"params\":";
let mut results = Vec::new();
if let Some(pos) = find_toplevel_key(json, "params") {
let after = &json[pos + needle.len()..];
let after = after.trim_start();
if after.starts_with('[') {
let bracket_end = find_matching_bracket(after);
let inner = &after[1..bracket_end];
for obj in inner.split("},") {
if results.len() >= MAX_ARRAY_ITEMS {
break;
}
let name = extract_json_string(obj, "name");
let ty = extract_json_string(obj, "type");
if !name.is_empty() {
results.push((name, ty));
}
}
}
}
results
}
pub(super) fn parse_pull_response(body: &str) -> PullResult {
PullResult {
hash: extract_json_string(body, "hash"),
source: extract_json_string(body, "source"),
module: extract_json_string(body, "module"),
params: extract_params_array(body),
return_ty: {
let rt = extract_json_string(body, "return_ty");
if rt.is_empty() {
None
} else {
Some(rt)
}
},
dependencies: extract_json_array_strings(body, "dependencies"),
requires: extract_json_array_strings(body, "requires"),
ensures: extract_json_array_strings(body, "ensures"),
}
}
pub(super) fn parse_search_response(body: &str) -> Vec<SearchResult> {
let mut results = Vec::new();
let needle = "\"results\":[";
if let Some(pos) = body.find(needle) {
let after = &body[pos + needle.len() - 1..]; // include the [
let bracket_end = find_matching_bracket(after);
let inner = &after[1..bracket_end];
for obj in inner.split("},{") {
if results.len() >= MAX_ARRAY_ITEMS {
break;
}
let name = extract_json_string(obj, "name");
let hash = extract_json_string(obj, "hash");
let module = extract_json_string(obj, "module");
let signature = extract_json_string(obj, "signature");
let verified = extract_json_bool(obj, "verified");
let tags = extract_json_array_strings(obj, "tags");
if !hash.is_empty() {
results.push(SearchResult {
name,
hash,
module,
signature,
verified,
tags,
});
}
}
}
results
}
trident/src/package/registry/json.rs
ฯ 0.0%
use *;
/// Maximum length for a single JSON string value (1 MB).
const MAX_STRING_LEN: usize = 1_000_000;
/// Maximum number of items in a JSON array.
const MAX_ARRAY_ITEMS: usize = 10_000;
pub
/// Find a top-level JSON key (depth 1) and return its byte offset.
/// Skips keys nested inside arrays or sub-objects by tracking
/// brace/bracket nesting while being aware of JSON strings.
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub