Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/containers/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ rust_library(
srcs = glob(["**/*.rs"]),
edition = "2021",
visibility = ["//visibility:public"],
deps = ["//src/elementary"],
)

rust_test(
Expand Down
3 changes: 3 additions & 0 deletions src/containers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ license-file = "../../LICENSE.md"

[lib]
path = "lib.rs"

[dependencies]
elementary.workspace = true
6 changes: 3 additions & 3 deletions src/containers/fixed_capacity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ mod queue;
mod string;
mod vec;

pub use self::queue::FixedCapacityQueue;
pub use self::string::FixedCapacityString;
pub use self::vec::FixedCapacityVec;
pub use self::queue::{FixedCapacityQueue, FixedCapacityQueueIn};
pub use self::string::{FixedCapacityString, FixedCapacityStringIn};
pub use self::vec::{FixedCapacityVec, FixedCapacityVecIn};
63 changes: 47 additions & 16 deletions src/containers/fixed_capacity/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,63 +11,94 @@
// SPDX-License-Identifier: Apache-2.0
// *******************************************************************************

use core::ops;

use crate::generic::queue::GenericQueue;
use crate::storage::Heap;
use core::ops;
use elementary::{BasicAllocator, HeapAllocator, GLOBAL_ALLOCATOR};

/// A fixed-capacity queue.
/// A fixed-capacity queue, using provided allocator.
///
/// The queue can hold between 0 and `CAPACITY` elements, and behaves similarly to Rust's `VecDeque`,
/// except that it allocates memory immediately on construction, and can't shrink or grow.
pub struct FixedCapacityQueue<T> {
inner: GenericQueue<T, Heap<T>>,
pub struct FixedCapacityQueueIn<'alloc, T, A: BasicAllocator> {
inner: GenericQueue<T, Heap<'alloc, T, A>>,
}

impl<T> FixedCapacityQueue<T> {
impl<'alloc, T, A: BasicAllocator> FixedCapacityQueueIn<'alloc, T, A> {
/// Creates an empty queue and allocates memory for up to `capacity` elements, where `capacity <= u32::MAX`.
///
/// # Panics
///
/// - Panics if `capacity > u32::MAX`.
/// - Panics if the memory allocation fails.
#[must_use]
pub fn new(capacity: usize) -> Self {
pub fn new(capacity: usize, alloc: &'alloc A) -> Self {
assert!(
capacity <= u32::MAX as usize,
"FixedQueue can hold at most u32::MAX elements"
);
Self {
inner: GenericQueue::new(capacity as u32),
}

let storage = Heap::new(capacity as u32, alloc);
let inner = GenericQueue::new(storage);
Self { inner }
}
}

impl<T> Drop for FixedCapacityQueue<T> {
impl<T, A: BasicAllocator> Drop for FixedCapacityQueueIn<'_, T, A> {
fn drop(&mut self) {
self.inner.clear();
}
}

impl<T> ops::Deref for FixedCapacityQueue<T> {
type Target = GenericQueue<T, Heap<T>>;
impl<'alloc, T, A: BasicAllocator> ops::Deref for FixedCapacityQueueIn<'alloc, T, A> {
type Target = GenericQueue<T, Heap<'alloc, T, A>>;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl<T> ops::DerefMut for FixedCapacityQueue<T> {
impl<T, A: BasicAllocator> ops::DerefMut for FixedCapacityQueueIn<'_, T, A> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

/// A fixed-capacity queue, using global allocator.
/// Refer to [`FixedCapacityQueueIn`] for more information.
pub struct FixedCapacityQueue<T>(FixedCapacityQueueIn<'static, T, HeapAllocator>);

impl<T> FixedCapacityQueue<T> {
/// Creates an empty queue and allocates memory for up to `capacity` elements, where `capacity <= u32::MAX`.
///
/// # Panics
///
/// - Panics if `capacity > u32::MAX`.
/// - Panics if the memory allocation fails.
#[must_use]
pub fn new(capacity: usize) -> Self {
Self(FixedCapacityQueueIn::new(capacity, &GLOBAL_ALLOCATOR))
}
}

impl<T> ops::Deref for FixedCapacityQueue<T> {
type Target = GenericQueue<T, Heap<'static, T, HeapAllocator>>;

fn deref(&self) -> &Self::Target {
&self.0.inner
}
}

impl<T> ops::DerefMut for FixedCapacityQueue<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0.inner
}
}

#[cfg(test)]
mod tests {
use std::collections::VecDeque;

use super::*;
use std::collections::VecDeque;

fn to_vec<T: Copy>((first, second): (&[T], &[T])) -> Vec<T> {
let mut elements = first.to_vec();
Expand Down
100 changes: 79 additions & 21 deletions src/containers/fixed_capacity/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,24 @@
// SPDX-License-Identifier: Apache-2.0
// *******************************************************************************

use core::fmt;
use core::ops;

use crate::generic::string::GenericString;
use crate::storage::Heap;
use core::fmt;
use core::ops;
use elementary::GLOBAL_ALLOCATOR;
use elementary::{BasicAllocator, HeapAllocator};

/// A fixed-capacity Unicode string.
/// A fixed-capacity Unicode string, using provided allocator..
///
/// Note that the string is encoded as UTF-8, so each character (Unicode codepoint) requires between 1 and 4 bytes of storage.
///
/// The string can hold between 0 and `CAPACITY` **bytes**, and behaves similarly to Rust's `String`,
/// except that it allocates memory immediately on construction, and can't shrink or grow.
pub struct FixedCapacityString {
inner: GenericString<Heap<u8>>,
pub struct FixedCapacityStringIn<'alloc, A: BasicAllocator> {
inner: GenericString<Heap<'alloc, u8, A>>,
}

impl FixedCapacityString {
impl<'alloc, A: BasicAllocator> FixedCapacityStringIn<'alloc, A> {
/// Creates an empty string and allocates memory for up to `capacity` bytes, where `capacity <= u32::MAX`.
///
/// Note that the string is encoded as UTF-8, so each character (Unicode codepoint) requires between 1 and 4 bytes of storage.
Expand All @@ -37,14 +38,15 @@ impl FixedCapacityString {
/// - Panics if `capacity > u32::MAX`.
/// - Panics if the memory allocation fails.
#[must_use]
pub fn new(capacity: usize) -> Self {
pub fn new(capacity: usize, alloc: &'alloc A) -> Self {
assert!(
capacity <= u32::MAX as usize,
"FixedCapacityString can hold at most u32::MAX bytes"
);
Self {
inner: GenericString::new(capacity as u32),
}

let storage = Heap::new(capacity as u32, alloc);
let inner = GenericString::new(storage);
Self { inner }
}

/// Tries to create an empty string for up to `capacity` bytes, where `capacity <= u32::MAX`.
Expand All @@ -53,49 +55,105 @@ impl FixedCapacityString {
///
/// Returns `None` if `capacity > u32::MAX`, or if the memory allocation fails.
#[must_use]
pub fn try_new(capacity: usize) -> Option<Self> {
pub fn try_new(capacity: usize, alloc: &'alloc A) -> Option<Self> {
if capacity <= u32::MAX as usize {
Some(Self {
inner: GenericString::try_new(capacity as u32)?,
})
let storage = Heap::try_new(capacity as u32, alloc)?;
let inner = GenericString::new(storage);
Some(Self { inner })
} else {
None
}
}
}

impl Drop for FixedCapacityString {
impl<A: BasicAllocator> Drop for FixedCapacityStringIn<'_, A> {
fn drop(&mut self) {
self.inner.clear();
}
}

impl ops::Deref for FixedCapacityString {
type Target = GenericString<Heap<u8>>;
impl<'alloc, A: BasicAllocator> ops::Deref for FixedCapacityStringIn<'alloc, A> {
type Target = GenericString<Heap<'alloc, u8, A>>;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl ops::DerefMut for FixedCapacityString {
impl<A: BasicAllocator> ops::DerefMut for FixedCapacityStringIn<'_, A> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

impl fmt::Display for FixedCapacityString {
impl<A: BasicAllocator> fmt::Display for FixedCapacityStringIn<'_, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_str(), f)
}
}

impl fmt::Debug for FixedCapacityString {
impl<A: BasicAllocator> fmt::Debug for FixedCapacityStringIn<'_, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_str(), f)
}
}

/// A fixed-capacity Unicode string, using global allocator.
/// Refer to [`FixedCapacityStringIn`] for more information.
pub struct FixedCapacityString(FixedCapacityStringIn<'static, HeapAllocator>);

impl FixedCapacityString {
/// Creates an empty string and allocates memory for up to `capacity` bytes, where `capacity <= u32::MAX`.
///
/// Note that the string is encoded as UTF-8, so each character (Unicode codepoint) requires between 1 and 4 bytes of storage.
///
/// # Panics
///
/// - Panics if `capacity > u32::MAX`.
/// - Panics if the memory allocation fails.
#[must_use]
pub fn new(capacity: usize) -> Self {
Self(FixedCapacityStringIn::new(capacity, &GLOBAL_ALLOCATOR))
}

/// Tries to create an empty string for up to `capacity` bytes, where `capacity <= u32::MAX`.
///
/// Note that the string is encoded as UTF-8, so each character (Unicode codepoint) requires between 1 and 4 bytes of storage.
///
/// Returns `None` if `capacity > u32::MAX`, or if the memory allocation fails.
#[must_use]
pub fn try_new(capacity: usize) -> Option<Self> {
let inner = FixedCapacityStringIn::try_new(capacity, &GLOBAL_ALLOCATOR)?;
Some(Self(inner))
}
}

impl ops::Deref for FixedCapacityString {
type Target = GenericString<Heap<'static, u8, HeapAllocator>>;

fn deref(&self) -> &Self::Target {
&self.0.inner
}
}

impl ops::DerefMut for FixedCapacityString {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0.inner
}
}

impl fmt::Display for FixedCapacityString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.0.as_str(), f)
}
}

impl fmt::Debug for FixedCapacityString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.0.as_str(), f)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading
Loading