├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENCE-APACHE ├── LICENCE-MIT ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | matrix: 7 | allow_failures: 8 | - rust: nightly 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "region_buffer" 3 | version = "0.1.5" 4 | authors = ["Aaron Power "] 5 | edition = "2018" 6 | categories = ["data-structures"] 7 | keywords = ["region", "buffer", "shared", "mutable", "reference"] 8 | license = "MIT/Apache-2.0" 9 | description = "A growable array allowing for multiple mutable non overlapping regions" 10 | repository = "https://github.com/Aaronepower/region_buffer.git" 11 | 12 | [badges] 13 | [badges.travis-ci] 14 | repository = "Aaronepower/region_buffer" 15 | 16 | 17 | [dependencies] 18 | -------------------------------------------------------------------------------- /LICENCE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Aaron Power 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /LICENCE-MIT: -------------------------------------------------------------------------------- 1 | MIT License (MIT) 2 | 3 | Copyright (c) 2016 Aaron Power 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Region Buffer 2 | [![Linux build status](https://img.shields.io/travis/Aaronepower/region_buffer.svg?branch=master)](https://travis-ci.org/Aaronepower/region_buffer) 3 | [![](https://img.shields.io/crates/d/region_buffer.svg)](https://crates.io/crates/region_buffer) 4 | [![](https://img.shields.io/github/issues-raw/Aaronepower/region_buffer.svg)](https://github.com/Aaronepower/region_buffer/issues) 5 | [![](https://tokei.rs/b1/github/Aaronepower/region_buffer?category=code)](https://github.com/Aaronepower/region_buffer) 6 | [![Documentation](https://docs.rs/region_buffer/badge.svg)](https://docs.rs/region_buffer/) 7 | [![Donate using Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/Aaronepower/donate) 8 | 9 | A growable array allowing for multiple mutable non overlapping regions from 10 | the same `Vec`. 11 | 12 | ```toml 13 | region_buffer = "0.1" 14 | ``` 15 | 16 | # Examples 17 | 18 | ```rust 19 | use region_buffer::RegionBuffer; 20 | let mut buffer = RegionBuffer::new(); 21 | 22 | buffer.push(1); 23 | buffer.push(2); 24 | 25 | assert_eq!(buffer.len(), 2); 26 | 27 | let mut a = buffer.get_mut(0); 28 | let mut b = buffer.get_mut(1); 29 | 30 | assert_eq!(*a, 1); 31 | assert_eq!(*b, 2); 32 | 33 | *a = *b; 34 | *b = 3; 35 | 36 | assert_eq!(*a, 2); 37 | assert_eq!(*b, 3); 38 | ``` 39 | There is a `region_buffer` macro provided to make initialisation more 40 | convenient. 41 | ```rust 42 | #[macro_use] 43 | extern crate region_buffer; 44 | 45 | fn main() { 46 | let strings = region_buffer!["Hello", "World", "!"]; 47 | 48 | let mut greeting = strings.get_mut(0); 49 | let mut noun = strings.get_mut(1); 50 | let mut punctuation = strings.get_mut(2); 51 | 52 | *greeting = "Hallo"; 53 | *noun = "Peter"; 54 | *punctuation = "."; 55 | 56 | let string = format!("{} {}{}", greeting, noun, punctuation); 57 | assert_eq!(string, "Hallo Peter.") 58 | } 59 | ``` 60 | The macro can also be used to specify and initialise large regions of 61 | memory. 62 | ```rust 63 | #[macro_use] 64 | extern crate region_buffer; 65 | 66 | type Slice<'a> = region_buffer::Slice<'a, u8>; 67 | 68 | fn main() { 69 | let memory = region_buffer![0; 0xFFFF]; 70 | 71 | let rom = memory.region(0, 0x800); 72 | let gpu = memory.region(0x800, 0x1600); 73 | let sound = memory.region(0x1600, 0x2400); 74 | let ram = memory.region(0x2400, 0xFFFF); 75 | 76 | let console = Console::new(rom, gpu, sound, ram); 77 | } 78 | ``` 79 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # region_buffer 2 | //! A growable array allowing for multiple mutable non overlapping regions from 3 | //! the same `Vec`. 4 | //! 5 | //! # Examples 6 | //! ``` 7 | //!# use region_buffer::RegionBuffer; 8 | //! let mut buffer = RegionBuffer::new(); 9 | //! 10 | //! buffer.push(1); 11 | //! buffer.push(2); 12 | //! 13 | //! assert_eq!(buffer.len(), 2); 14 | //! 15 | //! let mut a = buffer.get_mut(0); 16 | //! let mut b = buffer.get_mut(1); 17 | //! 18 | //! assert_eq!(*a, 1); 19 | //! assert_eq!(*b, 2); 20 | //! 21 | //! *a = *b; 22 | //! *b = 3; 23 | //! 24 | //! assert_eq!(*a, 2); 25 | //! assert_eq!(*b, 3); 26 | //! ``` 27 | //! There is a [`region_buffer`] macro provided to make initialisation more 28 | //! convenient. 29 | //! ``` 30 | //!# #[macro_use] 31 | //!# extern crate region_buffer; 32 | //! 33 | //!# fn main() { 34 | //! let strings = region_buffer!["Hello", "World", "!"]; 35 | //! 36 | //! let mut greeting = strings.get_mut(0); 37 | //! let mut noun = strings.get_mut(1); 38 | //! let mut punctuation = strings.get_mut(2); 39 | //! 40 | //! *greeting = "Hallo"; 41 | //! *noun = "Peter"; 42 | //! *punctuation = "."; 43 | //! 44 | //! let string = format!("{} {}{}", greeting, noun, punctuation); 45 | //! assert_eq!(string, "Hallo Peter.") 46 | //!# } 47 | //! ``` 48 | //! The macro can also be used to specify and initialise large regions of 49 | //! memory. 50 | //! ``` 51 | //!# #[macro_use] 52 | //!# extern crate region_buffer; 53 | //!# 54 | //!# type Slice<'a> = region_buffer::Slice<'a, u8>; 55 | //!# 56 | //!# struct Console; 57 | //!# impl Console { 58 | //!# fn new(_: Slice, _: Slice, _: Slice, _: Slice) {} 59 | //!# } 60 | //!# 61 | //!# fn main() { 62 | //! let memory = region_buffer![0; 0xFFFF]; 63 | //! 64 | //! let rom = memory.region(0, 0x800); 65 | //! let gpu = memory.region(0x800, 0x1600); 66 | //! let sound = memory.region(0x1600, 0x2400); 67 | //! let ram = memory.region(0x2400, 0xFFFF); 68 | //! 69 | //! let console = Console::new(rom, gpu, sound, ram); 70 | //!# } 71 | //! ``` 72 | //! 73 | //! [`region_buffer`]: macro.region_buffer.html 74 | 75 | #![deny(missing_docs)] 76 | 77 | use std::cell::UnsafeCell; 78 | use std::cmp::PartialEq; 79 | use std::collections::HashSet; 80 | use std::fmt; 81 | use std::ops::{Deref, DerefMut, Index, IndexMut}; 82 | use std::sync::RwLock; 83 | 84 | /// Creates a [`RegionBuffer`] containing the arguments. 85 | /// `region_buffer!` allows [`RegionBuffer`]s to be defined with the same syntax 86 | /// as array expressions. There are two forms of this macro: 87 | /// 88 | /// * Create a [`RegionBuffer`] containing a given list of elements: 89 | /// ``` 90 | ///# #[macro_use] extern crate region_buffer; 91 | /// let buf = region_buffer![1, 2, 3]; 92 | /// 93 | /// assert_eq!(*buf.get(0), 1); 94 | /// assert_eq!(*buf.get(1), 2); 95 | /// assert_eq!(*buf.get(2), 3); 96 | /// ``` 97 | /// 98 | /// * Create a [`RegionBuffer`] given element and length: 99 | /// ``` 100 | ///# #[macro_use] extern crate region_buffer; 101 | /// let buf = region_buffer![1; 3]; 102 | /// 103 | /// assert_eq!(*buf.region(0, 3), [1, 1, 1]); 104 | /// ``` 105 | /// 106 | /// Note that unlike array expressions this syntax supports all elements which 107 | /// implement `Clone` and the number of elements doesn't have to be a constant. 108 | /// This will use clone to duplicate an expression, so one should be careful 109 | /// using this with types having a nonstandard `Clone` implementation. 110 | /// 111 | /// For example, `region_buffer![Rc::new(1); 5]` will create a vector of five 112 | /// references to the same boxed integer value, not five references pointing to 113 | /// independently boxed integers. 114 | /// 115 | /// [`RegionBuffer`]: struct.RegionBuffer.html 116 | #[macro_export] 117 | macro_rules! region_buffer { 118 | ($($element:expr),*) => {{ 119 | let mut region_buffer = $crate::RegionBuffer::new(); 120 | 121 | $( 122 | region_buffer.push($element); 123 | )* 124 | 125 | region_buffer 126 | }}; 127 | 128 | ($element:expr; $len:expr) => {{ 129 | $crate::RegionBuffer::from_elements($element, $len) 130 | }} 131 | } 132 | 133 | /// A contiguous growable array type, allow you to obtain multiple mutable 134 | /// regions from it, as long these regions don't overlap. 135 | #[derive(Debug, Default)] 136 | pub struct RegionBuffer { 137 | region: UnsafeCell>, 138 | ranges: Ranges, 139 | } 140 | 141 | #[allow(clippy::new_without_default_derive)] 142 | impl RegionBuffer { 143 | 144 | /// Constructs a new, empty `RegionBuffer`. The buffer will not allocate 145 | /// until elements are pushed onto it. 146 | pub fn new() -> Self 147 | { 148 | Self { 149 | region: UnsafeCell::new(Vec::new()), 150 | ranges: Ranges::new(), 151 | } 152 | } 153 | 154 | /// Appends an element to the back of a collection. 155 | /// 156 | /// # Panics 157 | /// Panics if the number of elements in the buffer overflows a `usize`. 158 | pub fn push(&mut self, element: T) { 159 | unsafe { &mut *self.region.get() }.push(element) 160 | } 161 | 162 | /// Returns the number of elements in the buffer, also referred to as its 163 | /// 'length'. 164 | pub fn len(&self) -> usize { 165 | unsafe { &*self.region.get() }.len() 166 | } 167 | 168 | /// Returns `true` if the region buffer contains no elements. 169 | pub fn is_empty(&self) -> bool { 170 | unsafe { &*self.region.get() }.is_empty() 171 | } 172 | 173 | /// Shortens the buffer, keeping the first `len` elements and dropping the 174 | /// rest. If `len` is greater than the buffer's current length, this has no 175 | /// effect. 176 | /// 177 | /// Note that this method has no effect on the allocated capacity of the 178 | /// buffer. 179 | /// 180 | /// # Panics 181 | /// If `len` is less than an already borrowed region. 182 | pub fn truncate(&self, len: usize) { 183 | assert!( 184 | self.ranges.0.read().unwrap().0.iter().all(|(_, end)| len > *end), 185 | "Truncated into an already borrowed region" 186 | ); 187 | unsafe { &mut *self.region.get() }.truncate(len) 188 | } 189 | 190 | /// Provides a mutable reference to a region in the buffer, provided that 191 | /// region hasn't already been borrowed. 192 | /// 193 | /// # Panics 194 | /// If the region has already been borrowed. 195 | pub fn region(&self, start: usize, end: usize) -> Slice { 196 | self.ranges.insert(start, end); 197 | 198 | let data = &mut unsafe { &mut *self.region.get() }[start..end]; 199 | 200 | Slice::new(data, (start, end), &self.ranges) 201 | } 202 | 203 | /// Returns a single element from the buffer. The borrowing rules also apply 204 | /// to this single element, so you can't get a single element from an 205 | /// already borrowed region and vice versa. 206 | pub fn get(&self, index: usize) -> Element { 207 | self.ranges.insert(index, index + 1); 208 | 209 | Element::new(&unsafe { &*self.region.get() }[index], index, &self.ranges) 210 | } 211 | 212 | /// Returns a single mutable element from the buffer. The borrowing rules 213 | /// also apply to this single element, so you can't get a single element 214 | /// from an already borrowed region and vice versa. 215 | pub fn get_mut(&self, index: usize) -> ElementMut { 216 | self.ranges.insert(index, index + 1); 217 | 218 | ElementMut::new(&mut unsafe { &mut *self.region.get() }[index], index, &self.ranges) 219 | } 220 | 221 | } 222 | 223 | unsafe impl Sync for RegionBuffer {} 224 | 225 | impl RegionBuffer { 226 | /// Initialise a buffer of `len` size, with all elements initialised to 227 | /// `element`. 228 | pub fn from_elements(element: T, len: usize) -> Self { 229 | Self { 230 | region: UnsafeCell::new(vec![element; len]), 231 | ranges: Ranges::new(), 232 | } 233 | } 234 | 235 | /// Expands the region by `to` size, with all new elements initialised to 236 | /// `element`. 237 | pub fn expand(&mut self, to: usize, element: T) { 238 | let region = unsafe { &mut *self.region.get() }; 239 | region.reserve(to + 1); 240 | for _ in 0..to { 241 | region.push(element.clone()); 242 | } 243 | } 244 | 245 | } 246 | 247 | /// Represents a mutable slice into a region of memory. The region will be freed 248 | /// on `Drop`. 249 | #[derive(Debug)] 250 | pub struct Slice<'a, T: 'a> { 251 | data: &'a mut [T], 252 | points: (usize, usize), 253 | ranges: &'a Ranges, 254 | } 255 | 256 | impl<'a, T: 'a> Slice<'a, T> { 257 | fn new(data: &'a mut [T], points: (usize, usize), ranges: &'a Ranges) -> Self { 258 | Self { data, points, ranges } 259 | } 260 | } 261 | 262 | impl<'a, T: 'a> Drop for Slice<'a, T> { 263 | fn drop(&mut self) { 264 | self.ranges.0.write().unwrap().0.remove(&self.points); 265 | } 266 | } 267 | 268 | impl<'a, T: 'a> Deref for Slice<'a, T> { 269 | type Target = [T]; 270 | 271 | fn deref(&self) -> &Self::Target { 272 | &*self.data 273 | } 274 | } 275 | 276 | impl<'a, T: 'a> DerefMut for Slice<'a, T> { 277 | fn deref_mut(&mut self) -> &mut Self::Target { 278 | self.data 279 | } 280 | } 281 | 282 | impl<'a, T> Index for Slice<'a, T> { 283 | type Output = T; 284 | 285 | fn index(&self, index: usize) -> &Self::Output { 286 | &self.data[index] 287 | } 288 | } 289 | 290 | impl<'a, T> IndexMut for Slice<'a, T> { 291 | fn index_mut(&mut self, index: usize) -> &mut Self::Output { 292 | &mut self.data[index] 293 | } 294 | } 295 | 296 | impl<'a, T: PartialEq> PartialEq> for Slice<'a, T> { 297 | fn eq(&self, rhs: &Self) -> bool { 298 | self.data == rhs.data 299 | } 300 | } 301 | 302 | impl<'a, T: PartialEq> PartialEq<[T]> for Slice<'a, T> { 303 | fn eq(&self, rhs: &[T]) -> bool { 304 | self.data == rhs 305 | } 306 | } 307 | 308 | impl<'a, 'b, T: PartialEq> PartialEq<&'b mut [T]> for Slice<'a, T> { 309 | fn eq(&self, rhs: &&mut [T]) -> bool { 310 | self.data == *rhs 311 | } 312 | } 313 | 314 | /// A struct representing a single element from the `RegionBuffer`. When 315 | /// `Drop`ped the element's solitary region is freed. 316 | pub struct Element<'a, T: 'a> { 317 | data: &'a T, 318 | index: usize, 319 | parent: &'a Ranges, 320 | } 321 | 322 | impl<'a, T> Element<'a, T> { 323 | fn new(data: &'a T, index: usize, parent: &'a Ranges) -> Self { 324 | Self { data, index, parent } 325 | } 326 | } 327 | 328 | impl<'a, T> Deref for Element<'a, T> { 329 | type Target = T; 330 | 331 | fn deref(&self) -> &Self::Target { 332 | self.data 333 | } 334 | } 335 | 336 | impl<'a, T> Drop for Element<'a, T> { 337 | fn drop(&mut self) { 338 | self.parent.0.write().unwrap().0.remove(&(self.index, self.index + 1)); 339 | } 340 | } 341 | 342 | impl<'a, T: fmt::Debug> fmt::Debug for Element<'a, T> { 343 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 344 | self.data.fmt(f) 345 | } 346 | } 347 | 348 | impl<'a, T: fmt::Display> fmt::Display for Element<'a, T> { 349 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 350 | self.data.fmt(f) 351 | } 352 | } 353 | 354 | /// A struct representing a single mutable element from the `RegionBuffer`. When 355 | /// `Drop`ped the element's solitary region is freed. 356 | pub struct ElementMut<'a, T: 'a> { 357 | data: &'a mut T, 358 | index: usize, 359 | parent: &'a Ranges, 360 | } 361 | 362 | impl<'a, T> ElementMut<'a, T> { 363 | fn new(data: &'a mut T, index: usize, parent: &'a Ranges) -> Self { 364 | Self { data, index, parent } 365 | } 366 | } 367 | 368 | impl<'a, T> Deref for ElementMut<'a, T> { 369 | type Target = T; 370 | 371 | fn deref(&self) -> &Self::Target { 372 | self.data 373 | } 374 | } 375 | 376 | impl <'a, T> DerefMut for ElementMut<'a, T> { 377 | fn deref_mut(&mut self) -> &mut Self::Target { 378 | self.data 379 | } 380 | } 381 | 382 | impl<'a, T> Drop for ElementMut<'a, T> { 383 | fn drop(&mut self) { 384 | self.parent.0.write().unwrap().0.remove(&(self.index, self.index + 1)); 385 | } 386 | } 387 | 388 | impl<'a, T: fmt::Debug> fmt::Debug for ElementMut<'a, T> { 389 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 390 | self.data.fmt(f) 391 | } 392 | } 393 | 394 | impl<'a, T: fmt::Display> fmt::Display for ElementMut<'a, T> { 395 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 396 | self.data.fmt(f) 397 | } 398 | } 399 | 400 | #[derive(Debug, Default)] 401 | struct Ranges(RwLock); 402 | 403 | impl Ranges { 404 | fn new() -> Self { 405 | Ranges(RwLock::new(RangesInner::new())) 406 | } 407 | 408 | fn insert(&self, start: usize, end: usize) { 409 | let mut locked = self.0.write().unwrap(); 410 | if let Err(e) = locked.assert_region_is_free(start, end) { 411 | // Dropping to prevent poisoning 412 | drop(locked); 413 | panic!(e); 414 | } 415 | locked.0.insert((start, end)); 416 | } 417 | } 418 | 419 | #[derive(Debug, Default)] 420 | struct RangesInner(HashSet<(usize, usize)>); 421 | 422 | impl RangesInner { 423 | fn new() -> Self { 424 | RangesInner(HashSet::new()) 425 | } 426 | 427 | fn assert_region_is_free(&self, start: usize, end: usize) -> Result<(), String> { 428 | match self.is_region_borrowed(start, end) { 429 | Overlaps::None => Ok(()), 430 | error => Err(error.to_string()) 431 | } 432 | } 433 | 434 | fn is_region_borrowed(&self, start: usize, end: usize) -> Overlaps { 435 | for (used_start, used_end) in self.0.iter().map(|(x, y)| (*x, *y)) { 436 | if start >= used_start && start < used_end 437 | { 438 | return Overlaps::Start 439 | } else if end >= used_start && end <= used_end 440 | { 441 | return Overlaps::End 442 | } else if used_start >= start && used_end <= end { 443 | return Overlaps::StartAndEnd 444 | } 445 | } 446 | 447 | Overlaps::None 448 | } 449 | } 450 | 451 | #[derive(Debug, PartialEq)] 452 | enum Overlaps { 453 | None, 454 | Start, 455 | End, 456 | StartAndEnd, 457 | } 458 | 459 | impl fmt::Display for Overlaps { 460 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 461 | let s = match self { 462 | Overlaps::None => "No Overlapping regions", 463 | Overlaps::Start => "Start overlaps into borrowed region", 464 | Overlaps::End => "End overlaps into borrowed region", 465 | Overlaps::StartAndEnd => "Start and end overlaps into borrowed \ 466 | region", 467 | }; 468 | 469 | s.fmt(f) 470 | } 471 | } 472 | 473 | #[cfg(test)] 474 | mod tests { 475 | use super::*; 476 | 477 | #[test] 478 | fn basic_use() { 479 | let foo = region_buffer![0; 0x800]; 480 | 481 | println!("{:?}", foo); 482 | 483 | let mut region_a = foo.region(0, 0x400); 484 | 485 | for i in 0..0x400 { 486 | region_a[i] = i; 487 | } 488 | 489 | let mut region_b = foo.region(0x400, 0x800); 490 | 491 | for i in (0..0x400).rev() { 492 | region_b[i] = i; 493 | } 494 | 495 | region_b.sort(); 496 | 497 | assert_eq!(region_a, region_b); 498 | } 499 | 500 | #[test] 501 | #[should_panic(expected="Start overlaps into borrowed region")] 502 | fn starts_in_overlap() { 503 | let foo = region_buffer![0; 0x800]; 504 | 505 | let _a = foo.region(0, 0x400); 506 | let _b = foo.region(0, 0x300); 507 | } 508 | 509 | #[test] 510 | #[should_panic(expected="End overlaps into borrowed region")] 511 | fn ends_in_overlap() { 512 | let foo = region_buffer![0; 0x800]; 513 | 514 | let _a = foo.region(0x300, 0x400); 515 | let _b = foo.region(0, 0x350); 516 | } 517 | 518 | #[test] 519 | #[should_panic(expected="Start and end overlaps into borrowed region")] 520 | fn completely_overlaps() { 521 | let foo = region_buffer![0; 0x800]; 522 | 523 | let _a = foo.region(0x300, 0x400); 524 | let _b = foo.region(0, 0x800); 525 | } 526 | 527 | #[test] 528 | fn dropped_region() { 529 | let foo = region_buffer![0; 0x800]; 530 | 531 | let _ = foo.region(0, 0x400); 532 | let _ = foo.region(0, 0x400); 533 | } 534 | 535 | #[test] 536 | fn truncate() { 537 | let foo = region_buffer![1, 2, 3]; 538 | 539 | let _a = foo.get_mut(0); 540 | 541 | foo.truncate(2); 542 | } 543 | 544 | #[test] 545 | #[should_panic(expected="Truncated into an already borrowed region")] 546 | fn truncate_into_borrowed() { 547 | let foo = region_buffer![1, 2, 3]; 548 | 549 | let _a = foo.get_mut(2); 550 | 551 | foo.truncate(2); 552 | } 553 | } 554 | --------------------------------------------------------------------------------