1use crate::address::Address;
25use crate::error::ProgramError;
26
27pub const MAX_SEGMENT_BORROWS: usize = 16;
34
35#[derive(Clone, Copy, PartialEq, Eq, Debug)]
37#[repr(u8)]
38pub enum AccessKind {
39 Read = 0,
41 Write = 1,
43}
44
45#[inline(always)]
55fn address_fingerprint(address: &Address) -> u64 {
56 let bytes = address.as_array();
57 u64::from_le_bytes([
58 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
59 ])
60}
61
62#[inline(always)]
64fn address_eq(a: &Address, b: &Address) -> bool {
65 a.as_array() == b.as_array()
66}
67
68#[derive(Clone, Copy, Debug)]
75pub struct SegmentBorrow {
76 pub key_fp: u64,
78 pub key: Address,
83 pub offset: u32,
85 pub size: u32,
87 pub kind: AccessKind,
89}
90
91#[inline(always)]
93const fn ranges_overlap(a_off: u32, a_size: u32, b_off: u32, b_size: u32) -> bool {
94 let a_end = a_off as u64 + a_size as u64;
95 let b_end = b_off as u64 + b_size as u64;
96 !(a_end <= b_off as u64 || b_end <= a_off as u64)
98}
99
100pub struct SegmentBorrowRegistry {
118 entries: [SegmentBorrow; MAX_SEGMENT_BORROWS],
119 len: u8,
120}
121
122impl SegmentBorrowRegistry {
123 #[inline(always)]
125 pub const fn new() -> Self {
126 const EMPTY: SegmentBorrow = SegmentBorrow {
127 key_fp: 0,
128 key: Address::new([0u8; 32]),
129 offset: 0,
130 size: 0,
131 kind: AccessKind::Read,
132 };
133 Self {
134 entries: [EMPTY; MAX_SEGMENT_BORROWS],
135 len: 0,
136 }
137 }
138
139 #[inline(always)]
141 pub const fn len(&self) -> usize {
142 self.len as usize
143 }
144
145 #[inline(always)]
147 pub const fn is_empty(&self) -> bool {
148 self.len == 0
149 }
150
151 #[inline(always)]
156 pub fn register_leased_read(
157 &mut self,
158 key: &Address,
159 offset: u32,
160 size: u32,
161 ) -> Result<SegmentBorrow, ProgramError> {
162 let borrow = SegmentBorrow {
163 key_fp: address_fingerprint(key),
164 key: *key,
165 offset,
166 size,
167 kind: AccessKind::Read,
168 };
169 self.register(borrow)?;
170 Ok(borrow)
171 }
172
173 #[inline(always)]
175 pub fn register_leased_write(
176 &mut self,
177 key: &Address,
178 offset: u32,
179 size: u32,
180 ) -> Result<SegmentBorrow, ProgramError> {
181 let borrow = SegmentBorrow {
182 key_fp: address_fingerprint(key),
183 key: *key,
184 offset,
185 size,
186 kind: AccessKind::Write,
187 };
188 self.register(borrow)?;
189 Ok(borrow)
190 }
191
192 #[inline(always)]
198 pub fn register(&mut self, new: SegmentBorrow) -> Result<(), ProgramError> {
199 let len = self.len as usize;
200 if len >= MAX_SEGMENT_BORROWS {
201 return Err(ProgramError::AccountBorrowFailed);
202 }
203
204 let mut i = 0;
209 while i < len {
210 let existing = &self.entries[i];
211 if existing.key_fp == new.key_fp
212 && address_eq(&existing.key, &new.key)
213 && ranges_overlap(existing.offset, existing.size, new.offset, new.size)
214 {
215 match (existing.kind, new.kind) {
216 (AccessKind::Read, AccessKind::Read) => {}
217 _ => return Err(ProgramError::AccountBorrowFailed),
218 }
219 }
220 i += 1;
221 }
222
223 self.entries[len] = new;
224 self.len = (len + 1) as u8;
225 Ok(())
226 }
227
228 #[inline(always)]
230 pub fn register_read(
231 &mut self,
232 key: &Address,
233 offset: u32,
234 size: u32,
235 ) -> Result<(), ProgramError> {
236 self.register(SegmentBorrow {
237 key_fp: address_fingerprint(key),
238 key: *key,
239 offset,
240 size,
241 kind: AccessKind::Read,
242 })
243 }
244
245 #[inline(always)]
247 pub fn register_write(
248 &mut self,
249 key: &Address,
250 offset: u32,
251 size: u32,
252 ) -> Result<(), ProgramError> {
253 self.register(SegmentBorrow {
254 key_fp: address_fingerprint(key),
255 key: *key,
256 offset,
257 size,
258 kind: AccessKind::Write,
259 })
260 }
261
262 #[inline(always)]
267 pub fn release(&mut self, borrow: &SegmentBorrow) -> bool {
268 let len = self.len as usize;
269 let mut i = 0;
270 while i < len {
271 let existing = &self.entries[i];
272 if existing.key_fp == borrow.key_fp
273 && address_eq(&existing.key, &borrow.key)
274 && existing.offset == borrow.offset
275 && existing.size == borrow.size
276 && existing.kind == borrow.kind
277 {
278 let new_len = len - 1;
280 self.len = new_len as u8;
281 if i < new_len {
282 self.entries[i] = self.entries[new_len];
283 }
284 return true;
285 }
286 i += 1;
287 }
288 false
289 }
290
291 #[inline(always)]
293 pub fn clear(&mut self) {
294 self.len = 0;
295 }
296
297 #[inline(always)]
302 pub fn would_conflict(&self, proposed: &SegmentBorrow) -> bool {
303 let len = self.len as usize;
304 let mut i = 0;
305 while i < len {
306 let existing = &self.entries[i];
307 if existing.key_fp == proposed.key_fp
308 && address_eq(&existing.key, &proposed.key)
309 && ranges_overlap(
310 existing.offset,
311 existing.size,
312 proposed.offset,
313 proposed.size,
314 )
315 {
316 match (existing.kind, proposed.kind) {
317 (AccessKind::Read, AccessKind::Read) => {}
318 _ => return true,
319 }
320 }
321 i += 1;
322 }
323 false
324 }
325
326 #[inline(always)]
341 pub fn register_guard(
342 &mut self,
343 borrow: SegmentBorrow,
344 ) -> Result<SegmentBorrowGuard<'_>, ProgramError> {
345 self.register(borrow)?;
346 Ok(SegmentBorrowGuard {
347 registry: self,
348 borrow,
349 })
350 }
351
352 #[inline(always)]
354 pub fn register_guard_read(
355 &mut self,
356 key: &Address,
357 offset: u32,
358 size: u32,
359 ) -> Result<SegmentBorrowGuard<'_>, ProgramError> {
360 let borrow = SegmentBorrow {
361 key_fp: address_fingerprint(key),
362 key: *key,
363 offset,
364 size,
365 kind: AccessKind::Read,
366 };
367 self.register_guard(borrow)
368 }
369
370 #[inline(always)]
372 pub fn register_guard_write(
373 &mut self,
374 key: &Address,
375 offset: u32,
376 size: u32,
377 ) -> Result<SegmentBorrowGuard<'_>, ProgramError> {
378 let borrow = SegmentBorrow {
379 key_fp: address_fingerprint(key),
380 key: *key,
381 offset,
382 size,
383 kind: AccessKind::Write,
384 };
385 self.register_guard(borrow)
386 }
387
388 #[inline]
393 pub fn for_each<F: FnMut(&SegmentBorrow)>(&self, mut f: F) {
394 let len = self.len as usize;
395 let mut i = 0;
396 while i < len {
397 f(&self.entries[i]);
398 i += 1;
399 }
400 }
401
402 #[inline]
404 pub fn find_exact(
405 &self,
406 key: &Address,
407 offset: u32,
408 size: u32,
409 kind: AccessKind,
410 ) -> Option<&SegmentBorrow> {
411 let fp = address_fingerprint(key);
412 let len = self.len as usize;
413 let mut i = 0;
414 while i < len {
415 let e = &self.entries[i];
416 if e.key_fp == fp
417 && address_eq(&e.key, key)
418 && e.offset == offset
419 && e.size == size
420 && e.kind as u8 == kind as u8
421 {
422 return Some(e);
423 }
424 i += 1;
425 }
426 None
427 }
428}
429
430pub struct SegmentBorrowGuard<'a> {
436 registry: &'a mut SegmentBorrowRegistry,
437 borrow: SegmentBorrow,
438}
439
440impl<'a> SegmentBorrowGuard<'a> {
441 #[inline(always)]
443 pub fn kind(&self) -> AccessKind {
444 self.borrow.kind
445 }
446
447 #[inline(always)]
449 pub fn offset(&self) -> u32 {
450 self.borrow.offset
451 }
452
453 #[inline(always)]
455 pub fn size(&self) -> u32 {
456 self.borrow.size
457 }
458}
459
460impl<'a> Drop for SegmentBorrowGuard<'a> {
461 fn drop(&mut self) {
462 self.registry.release(&self.borrow);
463 }
464}
465
466#[cfg(kani)]
467mod kani_proofs {
468 use super::*;
469
470 #[kani::proof]
471 fn range_overlap_is_symmetric_for_arbitrary_u32s() {
472 let a_off: u32 = kani::any();
473 let a_size: u32 = kani::any();
474 let b_off: u32 = kani::any();
475 let b_size: u32 = kani::any();
476
477 assert_eq!(
478 ranges_overlap(a_off, a_size, b_off, b_size),
479 ranges_overlap(b_off, b_size, a_off, a_size)
480 );
481 }
482
483 #[kani::proof]
484 fn overlapping_write_blocks_same_account_accesses() {
485 let offset: u32 = kani::any();
486 let size: u32 = kani::any();
487 let delta: u32 = kani::any();
488 kani::assume(offset <= 1024);
489 kani::assume(size > 0 && size <= 64);
490 kani::assume(delta < size);
491
492 let key = Address::new([7u8; 32]);
493 let probe_offset = offset + delta;
494 let mut reg = SegmentBorrowRegistry::new();
495
496 assert!(reg.register_write(&key, offset, size).is_ok());
497 assert!(reg.register_read(&key, probe_offset, 1).is_err());
498 assert!(reg.register_write(&key, probe_offset, 1).is_err());
499 assert_eq!(reg.len(), 1);
500 }
501
502 #[kani::proof]
503 fn overlapping_reads_are_shared_for_same_account() {
504 let offset: u32 = kani::any();
505 let size: u32 = kani::any();
506 let delta: u32 = kani::any();
507 kani::assume(offset <= 1024);
508 kani::assume(size > 0 && size <= 64);
509 kani::assume(delta < size);
510
511 let key = Address::new([8u8; 32]);
512 let probe_offset = offset + delta;
513 let mut reg = SegmentBorrowRegistry::new();
514
515 assert!(reg.register_read(&key, offset, size).is_ok());
516 assert!(reg.register_read(&key, probe_offset, 1).is_ok());
517 assert_eq!(reg.len(), 2);
518 }
519
520 #[kani::proof]
521 fn fingerprint_collision_different_addresses_do_not_conflict() {
522 let key_a = Address::new([9u8; 32]);
523 let mut key_b_bytes = [9u8; 32];
524 key_b_bytes[8] = 10;
525 let key_b = Address::new(key_b_bytes);
526 let mut reg = SegmentBorrowRegistry::new();
527
528 assert_eq!(address_fingerprint(&key_a), address_fingerprint(&key_b));
529 assert_ne!(key_a.as_array(), key_b.as_array());
530 assert!(reg.register_write(&key_a, 0, 8).is_ok());
531 assert!(reg.register_write(&key_b, 0, 8).is_ok());
532 assert_eq!(reg.len(), 2);
533 }
534
535 #[kani::proof]
536 fn release_removes_exact_borrow_and_preserves_others() {
537 let key = Address::new([11u8; 32]);
538 let mut reg = SegmentBorrowRegistry::new();
539
540 let first = reg.register_leased_read(&key, 0, 8).unwrap();
541 let second = reg.register_leased_write(&key, 8, 8).unwrap();
542 assert!(reg.release(&first));
543
544 assert_eq!(reg.len(), 1);
545 assert!(reg.find_exact(&key, 0, 8, AccessKind::Read).is_none());
546 assert!(reg.find_exact(&key, 8, 8, AccessKind::Write).is_some());
547 assert!(reg.release(&second));
548 assert!(reg.is_empty());
549 }
550}
551
552#[cfg(test)]
555mod tests {
556 use super::*;
557 use crate::Address;
558
559 fn test_addr(seed: u8) -> Address {
560 Address::new([seed; 32])
561 }
562
563 #[test]
564 fn read_read_same_range_allowed() {
565 let mut reg = SegmentBorrowRegistry::new();
566 let key = test_addr(1);
567 assert!(reg.register_read(&key, 0, 8).is_ok());
568 assert!(reg.register_read(&key, 0, 8).is_ok());
569 assert_eq!(reg.len(), 2);
570 }
571
572 #[test]
573 fn read_write_same_range_rejected() {
574 let mut reg = SegmentBorrowRegistry::new();
575 let key = test_addr(1);
576 assert!(reg.register_read(&key, 0, 8).is_ok());
577 assert!(reg.register_write(&key, 0, 8).is_err());
578 }
579
580 #[test]
581 fn write_write_same_range_rejected() {
582 let mut reg = SegmentBorrowRegistry::new();
583 let key = test_addr(1);
584 assert!(reg.register_write(&key, 0, 8).is_ok());
585 assert!(reg.register_write(&key, 0, 8).is_err());
586 }
587
588 #[test]
589 fn write_read_same_range_rejected() {
590 let mut reg = SegmentBorrowRegistry::new();
591 let key = test_addr(1);
592 assert!(reg.register_write(&key, 0, 8).is_ok());
593 assert!(reg.register_read(&key, 0, 8).is_err());
594 }
595
596 #[test]
597 fn non_overlapping_write_write_allowed() {
598 let mut reg = SegmentBorrowRegistry::new();
599 let key = test_addr(1);
600 assert!(reg.register_write(&key, 0, 8).is_ok());
602 assert!(reg.register_write(&key, 8, 32).is_ok());
603 }
604
605 #[test]
606 fn partially_overlapping_rejected() {
607 let mut reg = SegmentBorrowRegistry::new();
608 let key = test_addr(1);
609 assert!(reg.register_write(&key, 0, 16).is_ok());
611 assert!(reg.register_write(&key, 8, 16).is_err());
612 }
613
614 #[test]
615 fn different_accounts_always_allowed() {
616 let mut reg = SegmentBorrowRegistry::new();
617 assert!(reg.register_write(&test_addr(1), 0, 8).is_ok());
618 assert!(reg.register_write(&test_addr(2), 0, 8).is_ok());
619 }
620
621 #[test]
622 fn release_then_reacquire() {
623 let mut reg = SegmentBorrowRegistry::new();
624 let key = test_addr(1);
625 let borrow = SegmentBorrow {
626 key_fp: address_fingerprint(&key),
627 key,
628 offset: 0,
629 size: 8,
630 kind: AccessKind::Write,
631 };
632 assert!(reg.register(borrow).is_ok());
633 assert!(reg.register_write(&key, 0, 8).is_err()); assert!(reg.release(&borrow));
635 assert!(reg.register_write(&key, 0, 8).is_ok()); }
637
638 #[test]
639 fn capacity_limit() {
640 let mut reg = SegmentBorrowRegistry::new();
641 for i in 0..MAX_SEGMENT_BORROWS {
642 assert!(reg.register_read(&test_addr(1), i as u32 * 8, 8).is_ok());
643 }
644 assert!(reg.register_read(&test_addr(1), 256, 8).is_err());
646 }
647
648 #[test]
649 fn would_conflict_does_not_mutate() {
650 let mut reg = SegmentBorrowRegistry::new();
651 let key = test_addr(1);
652 assert!(reg.register_write(&key, 0, 8).is_ok());
653 let proposed = SegmentBorrow {
654 key_fp: address_fingerprint(&key),
655 key,
656 offset: 0,
657 size: 8,
658 kind: AccessKind::Write,
659 };
660 assert!(reg.would_conflict(&proposed));
661 assert_eq!(reg.len(), 1); }
663
664 #[test]
665 fn adjacent_ranges_no_conflict() {
666 let mut reg = SegmentBorrowRegistry::new();
667 let key = test_addr(1);
668 assert!(reg.register_write(&key, 0, 8).is_ok());
670 assert!(reg.register_write(&key, 8, 8).is_ok());
671 }
672
673 #[test]
682 fn guard_auto_releases_write_on_drop() {
683 let mut reg = SegmentBorrowRegistry::new();
684 let key = test_addr(1);
685 {
686 let _guard = reg.register_guard_write(&key, 0, 8).unwrap();
687 }
689 assert_eq!(reg.len(), 0);
691 assert!(reg.register_write(&key, 0, 8).is_ok());
693 }
694
695 #[test]
696 fn guard_auto_releases_read_on_drop() {
697 let mut reg = SegmentBorrowRegistry::new();
698 let key = test_addr(1);
699 {
700 let _guard = reg.register_guard_read(&key, 0, 8).unwrap();
701 }
702 assert_eq!(reg.len(), 0);
703 assert!(reg.register_write(&key, 0, 8).is_ok());
705 }
706
707 #[test]
708 fn sequential_guards_reuse_slot() {
709 let mut reg = SegmentBorrowRegistry::new();
710 let key = test_addr(1);
711 for _ in 0..4 {
712 let _guard = reg.register_guard_write(&key, 0, 8).unwrap();
713 }
715 assert_eq!(reg.len(), 0);
716 }
717
718 #[test]
719 fn guard_accessors() {
720 let mut reg = SegmentBorrowRegistry::new();
721 let key = test_addr(1);
722 let guard = reg.register_guard_write(&key, 16, 32).unwrap();
723 assert_eq!(guard.kind(), AccessKind::Write);
724 assert_eq!(guard.offset(), 16);
725 assert_eq!(guard.size(), 32);
726 }
727
728 #[test]
729 fn guard_then_manual_register_ok() {
730 let mut reg = SegmentBorrowRegistry::new();
731 let key = test_addr(1);
732 {
733 let _guard = reg.register_guard_write(&key, 0, 8).unwrap();
734 }
735 assert!(reg.register_read(&key, 0, 8).is_ok());
737 assert_eq!(reg.len(), 1);
738 }
739}