rusty_cpp/analysis/
borrows.rs

1use 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            // Remove entry if no active borrows
80            if borrows.immutable.is_empty() && borrows.mutable.is_none() {
81                self.active_borrows.remove(target);
82            }
83        }
84    }
85}