Allocator growth (#407)

Adds growth to the block allocator.

- [x] No changelog update needed
This commit is contained in:
Corwin 2023-04-06 20:30:20 +01:00 committed by GitHub
commit 3e2c57f838
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 562 additions and 152 deletions

View file

@ -10,9 +10,9 @@ use core::convert::TryInto;
use core::ptr::NonNull; use core::ptr::NonNull;
use crate::interrupt::free; use crate::interrupt::free;
use bare_metal::{CriticalSection, Mutex}; use bare_metal::Mutex;
use super::bump_allocator::{BumpAllocator, StartEnd}; use super::bump_allocator::{BumpAllocatorInner, StartEnd};
use super::SendNonNull; use super::SendNonNull;
struct Block { struct Block {
@ -37,170 +37,309 @@ impl Block {
.expect("too large allocation") .expect("too large allocation")
.pad_to_align() .pad_to_align()
} }
pub fn layout() -> Layout {
Layout::new::<Block>().align_to(8).unwrap().pad_to_align()
}
} }
struct BlockAllocatorState { struct BlockAllocatorState {
first_free_block: Option<SendNonNull<Block>>, first_free_block: Option<SendNonNull<Block>>,
} }
struct BlockAllocatorInner {
inner_allocator: BumpAllocatorInner,
state: BlockAllocatorState,
}
pub struct BlockAllocator { pub struct BlockAllocator {
inner_allocator: BumpAllocator, inner: Mutex<RefCell<BlockAllocatorInner>>,
state: Mutex<RefCell<BlockAllocatorState>>,
} }
impl BlockAllocator { impl BlockAllocator {
pub(crate) const unsafe fn new(start: StartEnd) -> Self { pub(crate) const unsafe fn new(start: StartEnd) -> Self {
Self { Self {
inner_allocator: BumpAllocator::new(start), inner: Mutex::new(RefCell::new(BlockAllocatorInner::new(start))),
state: Mutex::new(RefCell::new(BlockAllocatorState {
first_free_block: None,
})),
} }
} }
#[doc(hidden)] #[doc(hidden)]
#[cfg(any(test, feature = "testing"))] #[cfg(any(test, feature = "testing"))]
pub unsafe fn number_of_blocks(&self) -> u32 { pub unsafe fn number_of_blocks(&self) -> u32 {
free(|key| { free(|key| self.inner.borrow(key).borrow_mut().number_of_blocks())
let mut state = self.state.borrow(key).borrow_mut();
let mut count = 0;
let mut list_ptr = &mut state.first_free_block;
while let Some(mut current) = list_ptr {
count += 1;
list_ptr = &mut current.as_mut().next;
}
count
})
}
/// Requests a brand new block from the inner bump allocator
fn new_block(&self, layout: Layout, cs: CriticalSection) -> Option<NonNull<u8>> {
let overall_layout = Block::either_layout(layout);
self.inner_allocator.alloc_critical(overall_layout, cs)
}
/// Merges blocks together to create a normalised list
unsafe fn normalise(&self) {
free(|key| {
let mut state = self.state.borrow(key).borrow_mut();
let mut list_ptr = &mut state.first_free_block;
while let Some(mut current) = list_ptr {
if let Some(next_elem) = current.as_mut().next {
let difference = next_elem
.as_ptr()
.cast::<u8>()
.offset_from(current.as_ptr().cast::<u8>());
let usize_difference: usize = difference
.try_into()
.expect("distances in alloc'd blocks must be positive");
if usize_difference == current.as_mut().size {
let current = current.as_mut();
let next = next_elem.as_ref();
current.size += next.size;
current.next = next.next;
continue;
}
}
list_ptr = &mut current.as_mut().next;
}
});
} }
pub unsafe fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> { pub unsafe fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
// find a block that this current request fits in free(|key| self.inner.borrow(key).borrow_mut().alloc(layout))
let full_layout = Block::either_layout(layout);
let (block_after_layout, block_after_layout_offset) = full_layout
.extend(Layout::new::<Block>().align_to(8).unwrap().pad_to_align())
.unwrap();
free(|key| {
let mut state = self.state.borrow(key).borrow_mut();
let mut current_block = state.first_free_block;
let mut list_ptr = &mut state.first_free_block;
// This iterates the free list until it either finds a block that
// is the exact size requested or a block that can be split into
// one with the desired size and another block header.
while let Some(mut current) = current_block {
let block_to_examine = current.as_mut();
if block_to_examine.size == full_layout.size() {
*list_ptr = block_to_examine.next;
return Some(current.cast());
} else if block_to_examine.size >= block_after_layout.size() {
// can split block
let split_block = Block {
size: block_to_examine.size - block_after_layout_offset,
next: block_to_examine.next,
};
let split_ptr = current
.as_ptr()
.cast::<u8>()
.add(block_after_layout_offset)
.cast();
*split_ptr = split_block;
*list_ptr = NonNull::new(split_ptr).map(SendNonNull);
return Some(current.cast());
}
current_block = block_to_examine.next;
list_ptr = &mut block_to_examine.next;
}
self.new_block(layout, key)
})
} }
pub unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { pub unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
free(|key| self.inner.borrow(key).borrow_mut().dealloc(ptr, layout));
}
pub unsafe fn dealloc_no_normalise(&self, ptr: *mut u8, layout: Layout) {
free(|key| {
self.inner
.borrow(key)
.borrow_mut()
.dealloc_no_normalise(ptr, layout);
});
}
pub unsafe fn grow(
&self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout,
) -> Option<NonNull<u8>> {
free(|key| {
self.inner
.borrow(key)
.borrow_mut()
.grow(ptr, layout, new_layout)
})
}
}
impl BlockAllocatorInner {
pub(crate) const unsafe fn new(start: StartEnd) -> Self {
Self {
inner_allocator: BumpAllocatorInner::new(start),
state: BlockAllocatorState {
first_free_block: None,
},
}
}
#[doc(hidden)]
#[cfg(any(test, feature = "testing"))]
pub unsafe fn number_of_blocks(&mut self) -> u32 {
let mut count = 0;
let mut list_ptr = &mut self.state.first_free_block;
while let Some(mut current) = list_ptr {
count += 1;
list_ptr = &mut current.as_mut().next;
}
count
}
/// Requests a brand new block from the inner bump allocator
fn new_block(&mut self, layout: Layout) -> Option<NonNull<u8>> {
let overall_layout = Block::either_layout(layout);
self.inner_allocator.alloc(overall_layout)
}
/// Merges blocks together to create a normalised list
unsafe fn normalise(&mut self) {
let mut list_ptr = &mut self.state.first_free_block;
while let Some(mut current) = list_ptr {
if let Some(next_elem) = current.as_mut().next {
let difference = next_elem
.as_ptr()
.cast::<u8>()
.offset_from(current.as_ptr().cast::<u8>());
let usize_difference: usize = difference
.try_into()
.expect("distances in alloc'd blocks must be positive");
if usize_difference == current.as_mut().size {
let current = current.as_mut();
let next = next_elem.as_ref();
current.size += next.size;
current.next = next.next;
continue;
}
}
list_ptr = &mut current.as_mut().next;
}
}
pub unsafe fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>> {
// find a block that this current request fits in
let full_layout = Block::either_layout(layout);
let mut list_ptr = &mut self.state.first_free_block;
// This iterates the free list until it either finds a block that
// is the exact size requested or a block that can be split into
// one with the desired size and another block header.
loop {
match list_ptr {
Some(mut current_block) => {
if let Some(alloc) = Self::allocate_into_block(list_ptr, full_layout) {
return Some(alloc);
}
list_ptr = &mut current_block.as_mut().next;
}
None => return self.new_block(layout),
}
}
}
/// splits a block in twain
unsafe fn allocate_into_block(
reference_to_block_pointer: &mut Option<SendNonNull<Block>>,
wanted_layout: Layout,
) -> Option<NonNull<u8>> {
let (extended_layout, offset) = wanted_layout.extend(Block::layout()).unwrap();
let mut examination_block_ptr = reference_to_block_pointer.unwrap().0;
let examination_block = examination_block_ptr.as_mut();
if examination_block.size == wanted_layout.size() {
*reference_to_block_pointer = examination_block.next;
Some(examination_block_ptr.cast())
} else if examination_block.size >= extended_layout.size() {
let split_block = Block {
size: examination_block.size - offset,
next: examination_block.next,
};
let split_block_ptr = examination_block_ptr
.as_ptr()
.cast::<u8>()
.add(offset)
.cast();
*split_block_ptr = split_block;
*reference_to_block_pointer = NonNull::new(split_block_ptr).map(SendNonNull);
Some(examination_block_ptr.cast())
} else {
None
}
}
pub unsafe fn grow(
&mut self,
ptr: *mut u8,
initial_layout: Layout,
desired_layout: Layout,
) -> Option<NonNull<u8>> {
let either_layout_initial = Block::either_layout(initial_layout);
let either_layout_desired = Block::either_layout(desired_layout);
let difference = Layout::from_size_align(
either_layout_desired.size() - either_layout_initial.size(),
either_layout_initial.align(),
)
.expect("should be able to construct difference layout");
if self.is_block_at_end(ptr, either_layout_initial) {
let _additional_space = self.inner_allocator.alloc(difference);
return NonNull::new(ptr);
}
// cases
// * Our block has no free block after it.
// * Our block has a free block after that we fit in.
// * Our block has a free block after that is too small.
// * UNIMPLEMENTED Out block has a free block after that is too small but that is at the end so we can bump allocate some more space.
let next_block = self.find_first_block_after(ptr);
if let Some(list_to_block) = next_block {
let is_block_directly_after = {
if let Some(block) = list_to_block {
block.0.as_ptr() == ptr.add(either_layout_initial.size()).cast()
} else {
false
}
};
if is_block_directly_after {
if let Some(_split) = Self::allocate_into_block(list_to_block, difference) {
return NonNull::new(ptr);
}
}
}
self.grow_copy(ptr, either_layout_initial, either_layout_desired)
}
unsafe fn grow_copy(
&mut self,
ptr: *mut u8,
initial_layout: Layout,
desired_layout: Layout,
) -> Option<NonNull<u8>> {
let new_ptr = self.alloc(desired_layout)?;
core::ptr::copy_nonoverlapping(ptr, new_ptr.as_ptr(), initial_layout.size());
self.dealloc(ptr, initial_layout);
Some(new_ptr)
}
unsafe fn is_block_at_end(&self, ptr: *mut u8, total_layout: Layout) -> bool {
self.inner_allocator.tip() == NonNull::new(ptr.add(total_layout.size()))
}
pub unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
self.dealloc_no_normalise(ptr, layout); self.dealloc_no_normalise(ptr, layout);
self.normalise(); self.normalise();
} }
pub unsafe fn dealloc_no_normalise(&self, ptr: *mut u8, layout: Layout) { /// Returns a reference to the pointer to the next block
let new_layout = Block::either_layout(layout).pad_to_align(); /// Useful because you can modify what points to the block and access the block
free(|key| { unsafe fn find_first_block_after(
let mut state = self.state.borrow(key).borrow_mut(); &mut self,
ptr: *mut u8,
) -> Option<&mut Option<SendNonNull<Block>>> {
let mut list_ptr = &mut self.state.first_free_block;
// note that this is a reference to a pointer loop {
let mut list_ptr = &mut state.first_free_block; match list_ptr {
Some(mut current_block) => {
// This searches the free list until it finds a block further along if current_block.as_ptr().cast() > ptr {
// than the block that is being freed. The newly freed block is then return Some(list_ptr);
// inserted before this block. If the end of the list is reached
// then the block is placed at the end with no new block after it.
loop {
match list_ptr {
Some(mut current_block) => {
if current_block.as_ptr().cast() > ptr {
let new_block_content = Block {
size: new_layout.size(),
next: Some(current_block),
};
*ptr.cast() = new_block_content;
*list_ptr = NonNull::new(ptr.cast()).map(SendNonNull);
break;
}
list_ptr = &mut current_block.as_mut().next;
} }
None => {
// reached the end of the list without finding a place to insert the value list_ptr = &mut current_block.as_mut().next;
}
None => return None,
}
}
}
pub unsafe fn dealloc_no_normalise(&mut self, ptr: *mut u8, layout: Layout) {
let new_layout = Block::either_layout(layout).pad_to_align();
// note that this is a reference to a pointer
let mut list_ptr = &mut self.state.first_free_block;
// This searches the free list until it finds a block further along
// than the block that is being freed. The newly freed block is then
// inserted before this block. If the end of the list is reached
// then the block is placed at the end with no new block after it.
loop {
match list_ptr {
Some(mut current_block) => {
if current_block.as_ptr().cast() > ptr {
let new_block_content = Block { let new_block_content = Block {
size: new_layout.size(), size: new_layout.size(),
next: None, next: Some(current_block),
}; };
*ptr.cast() = new_block_content; *ptr.cast() = new_block_content;
*list_ptr = NonNull::new(ptr.cast()).map(SendNonNull); *list_ptr = NonNull::new(ptr.cast()).map(SendNonNull);
break; break;
} }
list_ptr = &mut current_block.as_mut().next;
}
None => {
// reached the end of the list without finding a place to insert the value
let new_block_content = Block {
size: new_layout.size(),
next: None,
};
*ptr.cast() = new_block_content;
*list_ptr = NonNull::new(ptr.cast()).map(SendNonNull);
break;
} }
} }
}); }
} }
} }
@ -215,6 +354,24 @@ unsafe impl GlobalAlloc for BlockAllocator {
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.dealloc(ptr, layout); self.dealloc(ptr, layout);
} }
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
if new_size > layout.size() {
return match self.grow(ptr, layout, new_layout) {
Some(p) => p.as_ptr(),
None => core::ptr::null_mut(),
};
}
let new_ptr = GlobalAlloc::alloc(self, new_layout);
if !new_ptr.is_null() {
core::ptr::copy_nonoverlapping(ptr, new_ptr, core::cmp::min(layout.size(), new_size));
self.dealloc(ptr, layout);
}
new_ptr
}
} }
unsafe impl Allocator for BlockAllocator { unsafe impl Allocator for BlockAllocator {
@ -230,6 +387,42 @@ unsafe impl Allocator for BlockAllocator {
} }
} }
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
match self.grow(ptr.as_ptr(), old_layout, new_layout) {
Some(p) => Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
p.as_ptr(),
new_layout.size(),
))),
None => Err(core::alloc::AllocError),
}
}
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
let new_ptr = self
.grow(ptr.as_ptr(), old_layout, new_layout)
.ok_or(core::alloc::AllocError)?;
new_ptr
.as_ptr()
.add(old_layout.size())
.write_bytes(0, new_layout.size() - old_layout.size());
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
new_ptr.as_ptr(),
new_layout.size(),
)))
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
self.dealloc(ptr.as_ptr(), layout); self.dealloc(ptr.as_ptr(), layout);
} }

View file

@ -4,35 +4,41 @@ use core::ptr::NonNull;
use super::SendNonNull; use super::SendNonNull;
use crate::interrupt::free; use crate::interrupt::free;
use bare_metal::{CriticalSection, Mutex}; use bare_metal::Mutex;
pub(crate) struct StartEnd { pub(crate) struct StartEnd {
pub start: fn() -> usize, pub start: fn() -> usize,
pub end: fn() -> usize, pub end: fn() -> usize,
} }
pub(crate) struct BumpAllocator { pub(crate) struct BumpAllocatorInner {
current_ptr: Mutex<RefCell<Option<SendNonNull<u8>>>>, current_ptr: Option<SendNonNull<u8>>,
start_end: Mutex<StartEnd>, start_end: StartEnd,
} }
impl BumpAllocator { pub(crate) struct BumpAllocator {
inner: Mutex<RefCell<BumpAllocatorInner>>,
}
impl BumpAllocatorInner {
pub const fn new(start_end: StartEnd) -> Self { pub const fn new(start_end: StartEnd) -> Self {
Self { Self {
current_ptr: Mutex::new(RefCell::new(None)), current_ptr: None,
start_end: Mutex::new(start_end), start_end,
} }
} }
}
impl BumpAllocator { pub fn tip(&self) -> Option<NonNull<u8>> {
pub fn alloc_critical(&self, layout: Layout, cs: CriticalSection) -> Option<NonNull<u8>> { self.current_ptr.map(|x| x.0)
let mut current_ptr = self.current_ptr.borrow(cs).borrow_mut(); }
pub fn alloc(&mut self, layout: Layout) -> Option<NonNull<u8>> {
let current_ptr = &mut self.current_ptr;
let ptr = if let Some(c) = *current_ptr { let ptr = if let Some(c) = *current_ptr {
c.as_ptr() as usize c.as_ptr() as usize
} else { } else {
(self.start_end.borrow(cs).start)() (self.start_end.start)()
}; };
let alignment_bitmask = layout.align() - 1; let alignment_bitmask = layout.align() - 1;
@ -43,7 +49,7 @@ impl BumpAllocator {
let resulting_ptr = ptr + amount_to_add; let resulting_ptr = ptr + amount_to_add;
let new_current_ptr = resulting_ptr + layout.size(); let new_current_ptr = resulting_ptr + layout.size();
if new_current_ptr >= (self.start_end.borrow(cs).end)() { if new_current_ptr >= (self.start_end.end)() {
return None; return None;
} }
@ -51,8 +57,11 @@ impl BumpAllocator {
NonNull::new(resulting_ptr as *mut _) NonNull::new(resulting_ptr as *mut _)
} }
pub fn alloc_safe(&self, layout: Layout) -> Option<NonNull<u8>> { }
free(|key| self.alloc_critical(layout, key))
impl BumpAllocator {
fn alloc_safe(&self, layout: Layout) -> Option<NonNull<u8>> {
free(|key| self.inner.borrow(key).borrow_mut().alloc(layout))
} }
} }

View file

@ -292,4 +292,18 @@ mod test {
} }
} }
} }
#[test_case]
fn growth_works(_gba: &mut crate::Gba) {
let mut growing_vector = Vec::with_capacity(1);
for i in 0..1000 {
growing_vector.push(i);
growing_vector.reserve_exact(i + 2);
for (idx, elem) in growing_vector.iter().enumerate() {
assert_eq!(idx, *elem);
}
}
}
} }

View file

@ -176,7 +176,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253" checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253"
dependencies = [ dependencies = [
"hashbrown", "hashbrown 0.11.2",
"ttf-parser", "ttf-parser",
] ]
@ -200,6 +200,12 @@ dependencies = [
"ahash", "ahash",
] ]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "hound" name = "hound"
version = "3.5.0" version = "3.5.0"
@ -211,7 +217,6 @@ name = "hyperspace-roll"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"agb", "agb",
"bare-metal",
] ]
[[package]] [[package]]
@ -229,6 +234,16 @@ dependencies = [
"png", "png",
] ]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.140" version = "0.2.140"
@ -244,6 +259,12 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.3.7" version = "0.3.7"
@ -392,6 +413,15 @@ dependencies = [
"syn 2.0.8", "syn 2.0.8",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -422,11 +452,36 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.11" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
] ]
[[package]] [[package]]
@ -452,3 +507,12 @@ name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winnow"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [
"memchr",
]

View file

@ -176,7 +176,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253" checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253"
dependencies = [ dependencies = [
"hashbrown", "hashbrown 0.11.2",
"ttf-parser", "ttf-parser",
] ]
@ -200,6 +200,12 @@ dependencies = [
"ahash", "ahash",
] ]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "hound" name = "hound"
version = "3.5.0" version = "3.5.0"
@ -221,6 +227,16 @@ dependencies = [
"png", "png",
] ]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.6" version = "1.0.6"
@ -242,6 +258,12 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.3.7" version = "0.3.7"
@ -407,6 +429,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -446,11 +477,36 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.11" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
] ]
[[package]] [[package]]
@ -476,3 +532,12 @@ name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winnow"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [
"memchr",
]

View file

@ -191,7 +191,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253" checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253"
dependencies = [ dependencies = [
"hashbrown", "hashbrown 0.11.2",
"ttf-parser", "ttf-parser",
] ]
@ -224,6 +224,12 @@ dependencies = [
"ahash", "ahash",
] ]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "hound" name = "hound"
version = "3.5.0" version = "3.5.0"
@ -245,6 +251,16 @@ dependencies = [
"png", "png",
] ]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.140" version = "0.2.140"
@ -272,6 +288,12 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.3.7" version = "0.3.7"
@ -426,6 +448,15 @@ dependencies = [
"syn 2.0.8", "syn 2.0.8",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -483,11 +514,36 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.11" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
] ]
[[package]] [[package]]
@ -514,6 +570,15 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winnow"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "xml-rs" name = "xml-rs"
version = "0.8.4" version = "0.8.4"