use crate::error::Result;
use tower_lsp_server::ls_types::{Range, Uri};
pub const MAX_TOML_NESTING_DEPTH: usize = 64;
pub fn check_toml_nesting_depth(content: &str, max_depth: usize) -> std::result::Result<(), usize> {
let bytes = content.as_bytes();
let len = bytes.len();
let mut depth: usize = 0;
let mut i = 0;
let mut bracket_stack: Vec<u8> = Vec::new();
let mut dot_frames: Vec<usize> = vec![0];
let mut in_key = true;
while i < len {
match bytes[i] {
b'#' => {
while i < len && bytes[i] != b'\n' {
i += 1;
}
}
quote @ (b'"' | b'\'') => {
let is_multiline =
bytes.get(i + 1) == Some("e) && bytes.get(i + 2) == Some("e);
i = if is_multiline {
skip_multiline_string(bytes, i + 3, quote)
} else {
skip_single_line_string(bytes, i + 1, quote)
};
}
b'{' => {
depth += 1;
if depth > max_depth {
return Err(depth);
}
bracket_stack.push(b'{');
dot_frames.push(0);
in_key = true;
i += 1;
}
b'[' => {
depth += 1;
if depth > max_depth {
return Err(depth);
}
bracket_stack.push(b'[');
i += 1;
}
b'}' => {
if dot_frames.len() > 1 {
depth = depth.saturating_sub(dot_frames.pop().unwrap_or(0));
}
depth = depth.saturating_sub(1);
bracket_stack.pop();
in_key = false;
i += 1;
}
b']' => {
depth = depth.saturating_sub(1);
bracket_stack.pop();
i += 1;
}
b'.' if in_key => {
depth += 1;
if let Some(top) = dot_frames.last_mut() {
*top += 1;
}
if depth > max_depth {
return Err(depth);
}
i += 1;
}
b'=' if in_key => {
in_key = false;
i += 1;
}
b',' => {
match bracket_stack.last() {
Some(b'{') => {
if dot_frames.len() > 1 {
depth = depth.saturating_sub(dot_frames.pop().unwrap_or(0));
}
dot_frames.push(0);
in_key = true;
}
Some(b'[') => in_key = false,
_ => {}
}
i += 1;
}
b'\n' => {
if bracket_stack.is_empty() {
depth = depth.saturating_sub(dot_frames[0]);
dot_frames[0] = 0;
in_key = true;
}
i += 1;
}
_ => i += 1,
}
}
Ok(())
}
fn skip_single_line_string(bytes: &[u8], mut i: usize, quote: u8) -> usize {
let len = bytes.len();
while i < len {
if bytes[i] == b'\\' && quote == b'"' {
i += 2;
continue;
}
if bytes[i] == quote {
return i + 1;
}
i += 1;
}
i
}
fn skip_multiline_string(bytes: &[u8], mut i: usize, quote: u8) -> usize {
let len = bytes.len();
while i < len {
if bytes[i] == b'\\' && quote == b'"' {
i += 2;
continue;
}
if bytes[i] == quote {
let run_start = i;
while i < len && bytes[i] == quote {
i += 1;
}
if i - run_start >= 3 {
return i;
}
continue;
}
i += 1;
}
i
}
pub trait ManifestParser: Send + Sync {
type Dependency: DependencyInfo + Clone + Send + Sync;
type ParseResult: ParseResultInfo<Dependency = Self::Dependency> + Send;
fn parse(&self, content: &str, doc_uri: &Uri) -> Result<Self::ParseResult>;
}
pub trait DependencyInfo {
fn name(&self) -> &str;
fn name_range(&self) -> Range;
fn version_requirement(&self) -> Option<&str>;
fn version_range(&self) -> Option<Range>;
fn source(&self) -> DependencySource;
fn features(&self) -> &[String] {
&[]
}
}
pub trait ParseResultInfo {
type Dependency: DependencyInfo;
fn dependencies(&self) -> &[Self::Dependency];
fn workspace_root(&self) -> Option<&std::path::Path>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum DependencySource {
Registry,
Git {
url: String,
rev: Option<String>,
},
Path { path: String },
Url { url: String },
Sdk { sdk: String },
Workspace,
CustomRegistry { url: String },
}
impl DependencySource {
pub fn is_registry(&self) -> bool {
matches!(self, Self::Registry | Self::CustomRegistry { .. })
}
pub fn is_version_resolvable(&self) -> bool {
self.is_registry()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum LoadingState {
#[default]
Idle,
Loading,
Loaded,
Failed,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_check_toml_nesting_depth_empty_content() {
assert_eq!(check_toml_nesting_depth("", 4), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_no_brackets() {
assert_eq!(check_toml_nesting_depth("a = 1\nb = \"text\"\n", 4), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_exactly_at_max() {
let content = format!("a = {}1{}", "[".repeat(4), "]".repeat(4));
assert_eq!(check_toml_nesting_depth(&content, 4), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_one_over_max() {
let content = format!("a = {}1{}", "[".repeat(5), "]".repeat(5));
assert_eq!(check_toml_nesting_depth(&content, 4), Err(5));
}
#[test]
fn test_check_toml_nesting_depth_double_quoted_string_ignored() {
let content = r#"a = "[[[[[unbalanced brackets]]]]]""#;
assert_eq!(check_toml_nesting_depth(content, 0), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_single_quoted_string_ignored() {
let content = "a = '[[[[[unbalanced brackets]]]]]'";
assert_eq!(check_toml_nesting_depth(content, 0), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_escaped_quote_in_string() {
let content = r#"a = "embedded \" quote [[[[[""#;
assert_eq!(check_toml_nesting_depth(content, 0), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_comment_ignored() {
let content = "# [[[[[unbalanced comment brackets]]]]]\na = 1\n";
assert_eq!(check_toml_nesting_depth(content, 0), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_mixed_array_and_table_nesting() {
let content = "a = [{ b = [{ c = 1 }] }]";
assert_eq!(check_toml_nesting_depth(content, 4), Ok(()));
assert_eq!(check_toml_nesting_depth(content, 3), Err(4));
}
#[test]
fn test_check_toml_nesting_depth_inline_table_at_production_boundary() {
let depth = MAX_TOML_NESTING_DEPTH;
let at_max = format!("a = {}1{}", "{a=".repeat(depth), "}".repeat(depth));
assert_eq!(check_toml_nesting_depth(&at_max, depth), Ok(()));
let over_max = format!("a = {}1{}", "{a=".repeat(depth + 1), "}".repeat(depth + 1));
assert_eq!(check_toml_nesting_depth(&over_max, depth), Err(depth + 1));
}
#[test]
fn test_check_toml_nesting_depth_dotted_header_at_production_boundary() {
let depth = MAX_TOML_NESTING_DEPTH;
let at_max = format!("[{}a]\ny = 1\n", "a.".repeat(depth - 1));
assert_eq!(check_toml_nesting_depth(&at_max, depth), Ok(()));
let over_max = format!("[{}a]\ny = 1\n", "a.".repeat(depth));
assert_eq!(check_toml_nesting_depth(&over_max, depth), Err(depth + 1));
}
#[test]
fn test_check_toml_nesting_depth_dotted_key_at_production_boundary() {
let depth = MAX_TOML_NESTING_DEPTH;
let at_max = format!("a{} = 1\n", ".a".repeat(depth));
assert_eq!(check_toml_nesting_depth(&at_max, depth), Ok(()));
let over_max = format!("a{} = 1\n", ".a".repeat(depth + 1));
assert_eq!(check_toml_nesting_depth(&over_max, depth), Err(depth + 1));
}
#[test]
fn test_check_toml_nesting_depth_legitimate_dotted_keys_accepted() {
let content = r#"
[tool.poetry.dependencies]
requests = { version = "^2.28", extras = ["socks"] }
[libraries]
spring-boot = { module = "org.springframework.boot:spring-boot-starter", version.ref = "spring" }
[metrics]
cpu_load = 3.14
"#;
assert_eq!(
check_toml_nesting_depth(content, MAX_TOML_NESTING_DEPTH),
Ok(())
);
}
#[test]
fn test_check_toml_nesting_depth_dotted_array_of_tables_header_at_boundary() {
let depth = MAX_TOML_NESTING_DEPTH;
let at_max = format!("[[{}a]]\ny = 1\n", "a.".repeat(depth - 2));
assert_eq!(check_toml_nesting_depth(&at_max, depth), Ok(()));
let over_max = format!("[[{}a]]\ny = 1\n", "a.".repeat(depth - 1));
assert_eq!(check_toml_nesting_depth(&over_max, depth), Err(depth + 1));
}
#[test]
fn test_check_toml_nesting_depth_dotted_key_inside_bracket_header_composes() {
let content = "[a.b]\nc.d.e = {f.g = 1}\n";
assert_eq!(check_toml_nesting_depth(content, 4), Ok(()));
assert_eq!(check_toml_nesting_depth(content, 3), Err(4));
}
#[test]
fn test_check_toml_nesting_depth_many_dotted_key_statements_do_not_accumulate() {
let mut content = String::new();
for i in 0..500 {
content.push_str(&format!("k{i}.a.b.c = {i}\n"));
}
assert_eq!(check_toml_nesting_depth(&content, 4), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_sibling_inline_tables_in_array_do_not_accumulate() {
let mut content = String::from("deps = [\n");
for i in 0..200 {
content.push_str(&format!(
" {{ name = \"pkg{i}\", version.ref = \"v\" }},\n"
));
}
content.push_str("]\n");
assert_eq!(
check_toml_nesting_depth(&content, MAX_TOML_NESTING_DEPTH),
Ok(())
);
}
#[test]
fn test_check_toml_nesting_depth_multiline_literal_odd_quote_count() {
let content = format!("a = '''don't'''\nb = {}1{}", "[".repeat(5), "]".repeat(5));
assert_eq!(check_toml_nesting_depth(&content, 4), Err(5));
}
#[test]
fn test_check_toml_nesting_depth_rejects_original_sigabrt_payloads() {
let n = 20_000;
let payload1 = format!("a = '''don't'''\nb = {}1{}", "[".repeat(n), "]".repeat(n));
let payload2 = format!(
"a = \"\"\"x\"y\"\"\"\nb = {}1{}",
"[".repeat(n),
"]".repeat(n)
);
assert!(check_toml_nesting_depth(&payload1, MAX_TOML_NESTING_DEPTH).is_err());
assert!(check_toml_nesting_depth(&payload2, MAX_TOML_NESTING_DEPTH).is_err());
}
#[test]
fn test_check_toml_nesting_depth_multiline_basic_odd_quote_count() {
let content = format!(
"a = \"\"\"x\"y\"\"\"\nb = {}1{}",
"[".repeat(5),
"]".repeat(5)
);
assert_eq!(check_toml_nesting_depth(&content, 4), Err(5));
}
#[test]
fn test_check_toml_nesting_depth_multiline_basic_trailing_extra_quotes() {
let content = format!(
"a = \"\"\"ends with two quotes: \"\"\"\"\"\nb = {}1{}",
"[".repeat(5),
"]".repeat(5)
);
assert_eq!(check_toml_nesting_depth(&content, 4), Err(5));
}
#[test]
fn test_check_toml_nesting_depth_brackets_inside_multiline_string_ignored() {
let content = "d = \"\"\"\nsize is 5\" wide [[[unbalanced]]]\n\"\"\"\ne = 1\n";
assert_eq!(check_toml_nesting_depth(content, 0), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_multiline_literal_brackets_ignored() {
let content = "d = '''\n[[[unbalanced brackets]]]\n'''\ne = 1\n";
assert_eq!(check_toml_nesting_depth(content, 0), Ok(()));
}
#[test]
fn test_check_toml_nesting_depth_multiline_basic_one_extra_trailing_quote() {
let content = format!(
"a = \"\"\"ends with one quote: \"\"\"\"\nb = {}1{}",
"[".repeat(5),
"]".repeat(5)
);
assert_eq!(check_toml_nesting_depth(&content, 4), Err(5));
}
#[test]
fn test_check_toml_nesting_depth_adjacent_multiline_strings_then_nesting() {
let content = format!(
"a = \"\"\"first\"\"\"\nb = '''second'''\nc = {}1{}",
"[".repeat(5),
"]".repeat(5)
);
assert_eq!(check_toml_nesting_depth(&content, 4), Err(5));
}
#[test]
fn test_dependency_source_registry() {
let source = DependencySource::Registry;
assert_eq!(source, DependencySource::Registry);
assert!(source.is_registry());
assert!(source.is_version_resolvable());
}
#[test]
fn test_dependency_source_git() {
let source = DependencySource::Git {
url: "https://github.com/user/repo".into(),
rev: Some("main".into()),
};
assert!(!source.is_registry());
assert!(!source.is_version_resolvable());
match source {
DependencySource::Git { url, rev } => {
assert_eq!(url, "https://github.com/user/repo");
assert_eq!(rev, Some("main".into()));
}
_ => panic!("Expected Git source"),
}
}
#[test]
fn test_dependency_source_git_no_rev() {
let source = DependencySource::Git {
url: "https://github.com/user/repo".into(),
rev: None,
};
match source {
DependencySource::Git { url, rev } => {
assert_eq!(url, "https://github.com/user/repo");
assert!(rev.is_none());
}
_ => panic!("Expected Git source"),
}
}
#[test]
fn test_dependency_source_path() {
let source = DependencySource::Path {
path: "../local-crate".into(),
};
assert!(!source.is_registry());
match source {
DependencySource::Path { path } => {
assert_eq!(path, "../local-crate");
}
_ => panic!("Expected Path source"),
}
}
#[test]
fn test_dependency_source_url() {
let source = DependencySource::Url {
url: "https://example.com/package.whl".into(),
};
assert!(!source.is_registry());
assert!(!source.is_version_resolvable());
}
#[test]
fn test_dependency_source_sdk() {
let source = DependencySource::Sdk {
sdk: "flutter".into(),
};
assert!(!source.is_registry());
}
#[test]
fn test_dependency_source_workspace() {
let source = DependencySource::Workspace;
assert!(!source.is_registry());
assert!(!source.is_version_resolvable());
}
#[test]
fn test_dependency_source_custom_registry() {
let source = DependencySource::CustomRegistry {
url: "https://gems.example.com".into(),
};
assert!(source.is_registry());
assert!(source.is_version_resolvable());
}
#[test]
fn test_dependency_source_clone() {
let source1 = DependencySource::Git {
url: "https://example.com/repo".into(),
rev: Some("v1.0".into()),
};
let source2 = source1.clone();
assert_eq!(source1, source2);
}
#[test]
fn test_dependency_source_equality() {
let reg1 = DependencySource::Registry;
let reg2 = DependencySource::Registry;
assert_eq!(reg1, reg2);
let git1 = DependencySource::Git {
url: "https://example.com".into(),
rev: None,
};
let git2 = DependencySource::Git {
url: "https://example.com".into(),
rev: None,
};
assert_eq!(git1, git2);
let git3 = DependencySource::Git {
url: "https://different.com".into(),
rev: None,
};
assert_ne!(git1, git3);
}
#[test]
fn test_dependency_source_debug() {
let source = DependencySource::Registry;
let debug = format!("{:?}", source);
assert_eq!(debug, "Registry");
let git = DependencySource::Git {
url: "https://example.com".into(),
rev: Some("main".into()),
};
let git_debug = format!("{:?}", git);
assert!(git_debug.contains("https://example.com"));
assert!(git_debug.contains("main"));
}
#[test]
fn test_loading_state_default() {
assert_eq!(LoadingState::default(), LoadingState::Idle);
}
#[test]
fn test_loading_state_copy() {
let state = LoadingState::Loading;
let copied = state;
assert_eq!(state, copied);
}
#[test]
fn test_loading_state_debug() {
let debug_str = format!("{:?}", LoadingState::Loading);
assert_eq!(debug_str, "Loading");
}
#[test]
fn test_loading_state_all_variants() {
let variants = [
LoadingState::Idle,
LoadingState::Loading,
LoadingState::Loaded,
LoadingState::Failed,
];
for (i, v1) in variants.iter().enumerate() {
for (j, v2) in variants.iter().enumerate() {
if i == j {
assert_eq!(v1, v2);
} else {
assert_ne!(v1, v2);
}
}
}
}
}