rusty_cpp/analysis/
borrows.rs1use crate::ir::BorrowKind;
2use std::collections::{HashMap, HashSet};
3
4#[derive(Debug, Clone)]
5#[allow(dead_code)]
6pub struct BorrowChecker {
7 active_borrows: HashMap<String, ActiveBorrows>,
8}
9
10#[derive(Debug, Clone, Default)]
11#[allow(dead_code)]
12struct ActiveBorrows {
13 immutable: HashSet<String>,
14 mutable: Option<String>,
15}
16
17impl BorrowChecker {
18 #[allow(dead_code)]
19 pub fn new() -> Self {
20 Self {
21 active_borrows: HashMap::new(),
22 }
23 }
24
25 #[allow(dead_code)]
26 pub fn check_borrow(&self, target: &str, kind: &BorrowKind) -> Result<(), String> {
27 if let Some(borrows) = self.active_borrows.get(target) {
28 match kind {
29 BorrowKind::Immutable => {
30 if borrows.mutable.is_some() {
31 return Err(format!(
32 "Cannot borrow '{}' as immutable while it's mutably borrowed",
33 target
34 ));
35 }
36 }
37 BorrowKind::Mutable => {
38 if !borrows.immutable.is_empty() {
39 return Err(format!(
40 "Cannot borrow '{}' as mutable while it has {} immutable borrow(s)",
41 target,
42 borrows.immutable.len()
43 ));
44 }
45 if borrows.mutable.is_some() {
46 return Err(format!(
47 "Cannot borrow '{}' as mutable while it's already mutably borrowed",
48 target
49 ));
50 }
51 }
52 }
53 }
54 Ok(())
55 }
56
57 #[allow(dead_code)]
58 pub fn add_borrow(&mut self, target: String, borrower: String, kind: BorrowKind) {
59 let borrows = self.active_borrows.entry(target).or_default();
60
61 match kind {
62 BorrowKind::Immutable => {
63 borrows.immutable.insert(borrower);
64 }
65 BorrowKind::Mutable => {
66 borrows.mutable = Some(borrower);
67 }
68 }
69 }
70
71 #[allow(dead_code)]
72 pub fn release_borrow(&mut self, target: &str, borrower: &str) {
73 if let Some(borrows) = self.active_borrows.get_mut(target) {
74 borrows.immutable.remove(borrower);
75 if borrows.mutable.as_ref() == Some(&borrower.to_string()) {
76 borrows.mutable = None;
77 }
78
79 if borrows.immutable.is_empty() && borrows.mutable.is_none() {
81 self.active_borrows.remove(target);
82 }
83 }
84 }
85}