#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlockType {
None,
Object,
List,
DirectiveBlock,
}
#[derive(Debug)]
pub struct ScopeManager {
nesting_depth: i32,
current_block: BlockType,
block_stack: Vec<BlockType>,
accumulated_content: String,
}
impl ScopeManager {
pub fn new() -> Self {
Self {
nesting_depth: 0,
current_block: BlockType::None,
block_stack: Vec::new(),
accumulated_content: String::new(),
}
}
pub fn nesting_depth(&self) -> i32 {
self.nesting_depth
}
pub fn current_block(&self) -> BlockType {
self.current_block
}
pub fn in_nested_context(&self) -> bool {
self.nesting_depth > 0
}
pub fn enter_block(&mut self, block_type: BlockType) {
self.block_stack.push(self.current_block);
self.current_block = block_type;
self.nesting_depth += 1;
}
pub fn exit_block(&mut self) -> Result<(), ()> {
if self.nesting_depth <= 0 {
return Err(());
}
self.nesting_depth -= 1;
self.current_block = self.block_stack.pop().unwrap_or(BlockType::None);
Ok(())
}
pub fn accumulated_content(&self) -> &str {
&self.accumulated_content
}
pub fn accumulate(&mut self, text: &str) {
if !self.accumulated_content.is_empty() {
self.accumulated_content.push(' ');
}
self.accumulated_content.push_str(text);
}
pub fn clear_accumulated(&mut self) {
self.accumulated_content.clear();
}
pub fn block_is_complete(&self) -> bool {
self.nesting_depth == 0 && !self.accumulated_content.is_empty()
}
pub fn reset(&mut self) {
self.nesting_depth = 0;
self.current_block = BlockType::None;
self.block_stack.clear();
self.accumulated_content.clear();
}
}
impl Default for ScopeManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_nesting() {
let mut scope = ScopeManager::new();
assert_eq!(scope.nesting_depth(), 0);
assert!(!scope.in_nested_context());
scope.enter_block(BlockType::Object);
assert_eq!(scope.nesting_depth(), 1);
assert!(scope.in_nested_context());
assert_eq!(scope.current_block(), BlockType::Object);
scope.exit_block().unwrap();
assert_eq!(scope.nesting_depth(), 0);
assert!(!scope.in_nested_context());
}
#[test]
fn test_nested_objects() {
let mut scope = ScopeManager::new();
scope.enter_block(BlockType::Object);
scope.enter_block(BlockType::Object);
assert_eq!(scope.nesting_depth(), 2);
scope.exit_block().unwrap();
assert_eq!(scope.current_block(), BlockType::Object);
scope.exit_block().unwrap();
assert_eq!(scope.current_block(), BlockType::None);
}
#[test]
fn test_exit_without_enter() {
let mut scope = ScopeManager::new();
assert!(scope.exit_block().is_err());
}
#[test]
fn test_accumulation() {
let mut scope = ScopeManager::new();
assert_eq!(scope.accumulated_content(), "");
scope.accumulate("first");
assert_eq!(scope.accumulated_content(), "first");
scope.accumulate("second");
assert_eq!(scope.accumulated_content(), "first second");
scope.clear_accumulated();
assert_eq!(scope.accumulated_content(), "");
}
#[test]
fn test_block_complete() {
let mut scope = ScopeManager::new();
assert!(!scope.block_is_complete());
scope.accumulate("content");
assert!(scope.block_is_complete());
scope.clear_accumulated();
assert!(!scope.block_is_complete());
}
}