use crate::ingest::SemanticKind;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ToolHintOperation {
DeleteBody,
ChangeSignature,
ChangeType,
ReplaceBody,
Query,
Get,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ToolHints {
pub requires_full_context: bool,
pub apply_atomically: bool,
pub may_break_tests: bool,
pub requires_compilation: bool,
}
impl Default for ToolHints {
fn default() -> Self {
Self {
requires_full_context: false,
apply_atomically: true, may_break_tests: false,
requires_compilation: false,
}
}
}
impl ToolHints {
pub fn new() -> Self {
Self::default()
}
pub fn with_requires_full_context(mut self, value: bool) -> Self {
self.requires_full_context = value;
self
}
pub fn with_may_break_tests(mut self, value: bool) -> Self {
self.may_break_tests = value;
self
}
pub fn with_requires_compilation(mut self, value: bool) -> Self {
self.requires_compilation = value;
self
}
pub fn for_function_delete(is_public: bool) -> Self {
Self {
requires_full_context: false,
apply_atomically: true,
may_break_tests: is_public,
requires_compilation: true,
}
}
pub fn for_struct_modify(is_public: bool) -> Self {
Self {
requires_full_context: false,
apply_atomically: true,
may_break_tests: is_public,
requires_compilation: true,
}
}
pub fn for_body_replace() -> Self {
Self {
requires_full_context: false,
apply_atomically: true,
may_break_tests: false,
requires_compilation: false,
}
}
}
pub fn derive_tool_hints(
semantic_kind: SemanticKind,
is_public: bool,
operation: ToolHintOperation,
) -> ToolHints {
let requires_full_context = matches!(
(semantic_kind, operation),
(SemanticKind::Function, ToolHintOperation::DeleteBody)
| (SemanticKind::Function, ToolHintOperation::ReplaceBody)
| (SemanticKind::Trait, _)
);
let apply_atomically = true;
let may_break_tests = match (semantic_kind, is_public) {
(SemanticKind::Function, true) => true,
(SemanticKind::Trait, true) => true,
(SemanticKind::Type, true) => true,
_ => false,
};
let requires_compilation = match operation {
ToolHintOperation::ChangeType => true,
ToolHintOperation::ChangeSignature if is_public => true,
ToolHintOperation::DeleteBody if is_public => true,
_ => false,
};
ToolHints {
requires_full_context,
apply_atomically,
may_break_tests,
requires_compilation,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tool_hints_default() {
let hints = ToolHints::default();
assert_eq!(hints.requires_full_context, false);
assert_eq!(hints.apply_atomically, true);
assert_eq!(hints.may_break_tests, false);
assert_eq!(hints.requires_compilation, false);
}
#[test]
fn test_tool_hints_builder() {
let hints = ToolHints::new()
.with_requires_full_context(true)
.with_may_break_tests(true)
.with_requires_compilation(true);
assert_eq!(hints.requires_full_context, true);
assert_eq!(hints.apply_atomically, true); assert_eq!(hints.may_break_tests, true);
assert_eq!(hints.requires_compilation, true);
}
#[test]
fn test_tool_hints_serialization() {
let hints = ToolHints::new()
.with_requires_full_context(true)
.with_may_break_tests(false);
let json = serde_json::to_string(&hints).unwrap();
assert!(json.contains("\"requires_full_context\":true"));
assert!(json.contains("\"apply_atomically\":true"));
assert!(json.contains("\"may_break_tests\":false"));
}
#[test]
fn test_for_function_delete() {
let hints = ToolHints::for_function_delete(true);
assert_eq!(hints.requires_full_context, false);
assert_eq!(hints.apply_atomically, true);
assert_eq!(hints.may_break_tests, true); assert_eq!(hints.requires_compilation, true);
let hints_private = ToolHints::for_function_delete(false);
assert_eq!(hints_private.may_break_tests, false); }
#[test]
fn test_for_struct_modify() {
let hints = ToolHints::for_struct_modify(true);
assert_eq!(hints.requires_full_context, false);
assert_eq!(hints.apply_atomically, true);
assert_eq!(hints.may_break_tests, true); assert_eq!(hints.requires_compilation, true);
let hints_private = ToolHints::for_struct_modify(false);
assert_eq!(hints_private.may_break_tests, false); }
#[test]
fn test_for_body_replace() {
let hints = ToolHints::for_body_replace();
assert_eq!(hints.requires_full_context, false);
assert_eq!(hints.apply_atomically, true);
assert_eq!(hints.may_break_tests, false); assert_eq!(hints.requires_compilation, false); }
}