Mountain/ApplicationState/DTO/
RPCRangeDTO.rs

1//! # RPCRangeDTO
2//!
3//! # RESPONSIBILITY
4//! - Data transfer object for line/column-based text ranges
5//! - Serializable format for gRPC/IPC transmission
6//! - Used by Mountain to represent document edit ranges
7//!
8//! # FIELDS
9//! - StartLineNumber: Start line (0-based)
10//! - StartColumn: Start column (0-based)
11//! - EndLineNumber: End line (0-based)
12//! - EndColumn: End column (0-based)
13
14use serde::Deserialize;
15
16/// Maximum line number to prevent invalid ranges
17const MAX_LINE_NUMBER:usize = 1_000_000;
18
19/// Maximum column number to prevent invalid ranges
20const MAX_COLUMN_NUMBER:usize = 1_000_000;
21
22/// Represents a line and column-based range in a text document.
23/// Compatible with VS Code LSP position/range definitions.
24#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
25#[serde(rename_all = "PascalCase")]
26pub struct RPCRangeDTO {
27	/// Start line number (0-based)
28	pub StartLineNumber:usize,
29
30	/// Start column number (0-based)
31	pub StartColumn:usize,
32
33	/// End line number (0-based)
34	pub EndLineNumber:usize,
35
36	/// End column number (0-based)
37	pub EndColumn:usize,
38}
39
40impl RPCRangeDTO {
41	/// Creates a new RPCRangeDTO with validation.
42	///
43	/// # Arguments
44	/// * `StartLineNumber` - Start line (0-based)
45	/// * `StartColumn` - Start column (0-based)
46	/// * `EndLineNumber` - End line (0-based)
47	/// * `EndColumn` - End column (0-based)
48	///
49	/// # Returns
50	/// Result containing the DTO or validation error
51	pub fn New(StartLineNumber:usize, StartColumn:usize, EndLineNumber:usize, EndColumn:usize) -> Result<Self, String> {
52		// Validate line numbers
53		if StartLineNumber > MAX_LINE_NUMBER || EndLineNumber > MAX_LINE_NUMBER {
54			return Err(format!("Line numbers exceed maximum of {}", MAX_LINE_NUMBER));
55		}
56
57		// Validate column numbers
58		if StartColumn > MAX_COLUMN_NUMBER || EndColumn > MAX_COLUMN_NUMBER {
59			return Err(format!("Column numbers exceed maximum of {}", MAX_COLUMN_NUMBER));
60		}
61
62		// Validate position consistency
63		if StartLineNumber > EndLineNumber {
64			return Err("Start line number cannot be greater than end line number".to_string());
65		}
66
67		// Validate column consistency within same line
68		if StartLineNumber == EndLineNumber && StartColumn > EndColumn {
69			return Err("Start column cannot be greater than end column on the same line".to_string());
70		}
71
72		Ok(Self { StartLineNumber, StartColumn, EndLineNumber, EndColumn })
73	}
74
75	/// Checks if this is an empty range (start equals end).
76	pub fn IsEmpty(&self) -> bool { self.StartLineNumber == self.EndLineNumber && self.StartColumn == self.EndColumn }
77
78	/// Creates a range for inserting/replacing text at a specific position.
79	///
80	/// # Arguments
81	/// * `LineNumber` - Line number (0-based)
82	/// * `Column` - Column number (0-based)
83	///
84	/// # Returns
85	/// New RPCRangeDTO for position-based operations
86	pub fn Position(LineNumber:usize, Column:usize) -> Result<Self, String> {
87		Self::New(LineNumber, Column, LineNumber, Column)
88	}
89
90	/// Creates a range for a single line.
91	///
92	/// # Arguments
93	/// * `LineNumber` - Line number (0-based)
94	/// * `StartColumn` - Start column
95	/// * `EndColumn` - End column
96	///
97	/// # Returns
98	/// New RPCRangeDTO for single-line range
99	pub fn LineRange(LineNumber:usize, StartColumn:usize, EndColumn:usize) -> Result<Self, String> {
100		Self::New(LineNumber, StartColumn, LineNumber, EndColumn)
101	}
102}