diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..a618249 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,25 @@ +name: Rust + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + - name: install + run: rustup target add thumbv7em-none-eabi thumbv6m-none-eabi + - name: Build + run: ./ci.sh \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..25d323c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,289 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "as-slice" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" +dependencies = [ + "generic-array 0.12.4", + "generic-array 0.13.3", + "generic-array 0.14.4", + "stable_deref_trait", +] + +[[package]] +name = "atomic-polyfill" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b56892f5e1c2377f07ed6c7f5ca066d88b5ded79b052c44aa25f7d53c534227" +dependencies = [ + "cortex-m", +] + +[[package]] +name = "atomic-pool" +version = "0.1.0" +dependencies = [ + "as-slice", + "atomic-polyfill", + "defmt", + "log", + "stable_deref_trait", +] + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cortex-m" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643a210c1bdc23d0db511e2a576082f4ff4dcae9d0c37f50b431b8f8439d6d6b" +dependencies = [ + "bare-metal", + "bitfield", + "embedded-hal", + "volatile-register", +] + +[[package]] +name = "defmt" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "735ffd58278b045498da4ca9c5057a52faa6e18472cd63568b059ae592ca7602" +dependencies = [ + "defmt-macros", + "semver 0.11.0", +] + +[[package]] +name = "defmt-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d35887971a66a572654b37f2dd6a82e17a9dadf65935402fc910cf422955e994" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c816f778ec2147f95990a606795fe9dcc82781bcd98e222675c4103c2d250ea1" + +[[package]] +name = "embedded-hal" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.0.0", +] + +[[package]] +name = "nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +dependencies = [ + "vcell", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a55b018 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "atomic-pool" +version = "0.1.0" +authors = ["Dario Nieuwenhuis "] +edition = "2018" + +[features] +std = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] + +[dependencies] +atomic-polyfill = "0.1.1" +as-slice = { version = "0.1.4" } +stable_deref_trait = { version = "1.2.0", default-features = false } + +defmt = { version = "0.2.0", optional = true } +log = { version = "0.4.11", optional = true } diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..dacc57b --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020 Dario Nieuwenhuis + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..66fbb16 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# atomic-pool + +[![Documentation](https://docs.rs/atomic-pool/badge.svg)](https://docs.rs/atomic-pool) + +Statically allocated pool providing a std-like Box. + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/ci.sh b/ci.sh new file mode 100755 index 0000000..8949288 --- /dev/null +++ b/ci.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -euxo pipefail + +cargo build +cargo build --target thumbv6m-none-eabi +cargo build --target thumbv7em-none-eabi diff --git a/examples/simple.rs b/examples/simple.rs new file mode 100644 index 0000000..3e4a706 --- /dev/null +++ b/examples/simple.rs @@ -0,0 +1,31 @@ +use std::mem; + +use atomic_pool::{pool, Box}; + +#[derive(Debug)] +struct Packet(u32); + +pool!(PacketPool: [Packet; 4]); + +fn main() { + let box1 = Box::::new(Packet(1)); + println!("allocated: {:?}", box1); + + let box2 = Box::::new(Packet(2)); + println!("allocated: {:?}", box2); + + let box3 = Box::::new(Packet(3)); + println!("allocated: {:?}", box3); + + let box4 = Box::::new(Packet(4)); + println!("allocated: {:?}", box4); + + let box5 = Box::::new(Packet(5)); + println!("5th allocation fails because the pool is full: {:?}", box5); + + println!("dropping another allocation..."); + mem::drop(box1); + + let box5 = Box::::new(Packet(5)); + println!("5th allocation now works: {:?}", box5); +} diff --git a/src/atomic_bitset.rs b/src/atomic_bitset.rs new file mode 100644 index 0000000..735bd14 --- /dev/null +++ b/src/atomic_bitset.rs @@ -0,0 +1,44 @@ +use atomic_polyfill::{AtomicU32, Ordering}; + +use crate::fmt::{assert, *}; + +pub struct AtomicBitset +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + used: [AtomicU32; (N + 31) / 32], +} + +impl AtomicBitset +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + pub const fn new() -> Self { + const Z: AtomicU32 = AtomicU32::new(0); + Self { + used: [Z; (N + 31) / 32], + } + } + + pub fn alloc(&self) -> Option { + for (i, val) in self.used.iter().enumerate() { + let res = val.fetch_update(Ordering::AcqRel, Ordering::Acquire, |val| { + let n = val.trailing_ones() as usize + i * 32; + if n >= N { + None + } else { + Some(val | (1 << n)) + } + }); + if let Ok(val) = res { + let n = val.trailing_ones() as usize + i * 32; + return Some(n); + } + } + None + } + pub fn free(&self, i: usize) { + assert!(i < N); + self.used[i / 32].fetch_and(!(1 << ((i % 32) as u32)), Ordering::AcqRel); + } +} diff --git a/src/fmt.rs b/src/fmt.rs new file mode 100644 index 0000000..4da6976 --- /dev/null +++ b/src/fmt.rs @@ -0,0 +1,118 @@ +#![macro_use] + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +pub use fmt::*; + +#[cfg(feature = "defmt")] +mod fmt { + pub use defmt::{ + assert, assert_eq, assert_ne, debug, debug_assert, debug_assert_eq, debug_assert_ne, error, + info, panic, todo, trace, unreachable, unwrap, warn, + }; +} + +#[cfg(feature = "log")] +mod fmt { + pub use core::{ + assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo, + unreachable, + }; + pub use log::{debug, error, info, trace, warn}; +} + +#[cfg(not(any(feature = "defmt", feature = "log")))] +mod fmt { + #![macro_use] + + pub use core::{ + assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo, + unreachable, + }; + + #[macro_export] + macro_rules! trace { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! debug { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! info { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! warn { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! error { + ($($msg:expr),+ $(,)?) => { + () + }; + } +} + +#[cfg(not(feature = "defmt"))] +#[macro_export] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..21e6494 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,214 @@ +#![no_std] +#![feature(const_fn)] +#![feature(const_generics)] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + +mod atomic_bitset; + +use as_slice::{AsMutSlice, AsSlice}; +use core::cmp; +use core::hash::{Hash, Hasher}; +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::AtomicU32; + +use crate::atomic_bitset::AtomicBitset; +use crate::fmt::{assert, *}; + +pub trait PoolStorage { + fn alloc(&self) -> Option<*mut T>; + unsafe fn free(&self, p: *mut T); +} + +pub struct PoolStorageImpl +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + used: AtomicBitset, + data: MaybeUninit<[T; N]>, +} + +impl PoolStorageImpl +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + pub const fn new() -> Self { + Self { + used: AtomicBitset::new(), + data: MaybeUninit::uninit(), + } + } +} + +impl PoolStorage for PoolStorageImpl +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + fn alloc(&self) -> Option<*mut T> { + let n = self.used.alloc()?; + let origin = self.data.as_ptr() as *mut T; + Some(unsafe { origin.add(n) }) + } + + /// safety: p must be a pointer obtained from self.alloc that hasn't been freed yet. + unsafe fn free(&self, p: *mut T) { + let origin = self.data.as_ptr() as *mut T; + let n = p.offset_from(origin); + assert!(n >= 0); + assert!((n as usize) < N); + self.used.free(n as usize); + } +} + +pub trait Pool: 'static { + type Item: 'static; + type Storage: PoolStorage; + fn get() -> &'static Self::Storage; +} + +pub struct Box { + ptr: *mut P::Item, +} + +impl Box

{ + pub fn new(item: P::Item) -> Option { + let p = match P::get().alloc() { + Some(p) => p, + None => { + warn!("alloc failed!"); + return None; + } + }; + //trace!("allocated {:u32}", p as u32); + unsafe { p.write(item) }; + Some(Self { ptr: p }) + } +} + +impl Drop for Box

{ + fn drop(&mut self) { + unsafe { + //trace!("dropping {:u32}", self.ptr as u32); + self.ptr.drop_in_place(); + P::get().free(self.ptr); + }; + } +} + +unsafe impl Send for Box

where P::Item: Send {} + +unsafe impl Sync for Box

where P::Item: Sync {} + +unsafe impl stable_deref_trait::StableDeref for Box

{} + +impl AsSlice for Box

+where + P::Item: AsSlice, +{ + type Element = ::Element; + + fn as_slice(&self) -> &[Self::Element] { + self.deref().as_slice() + } +} + +impl AsMutSlice for Box

+where + P::Item: AsMutSlice, +{ + fn as_mut_slice(&mut self) -> &mut [Self::Element] { + self.deref_mut().as_mut_slice() + } +} + +impl Deref for Box

{ + type Target = P::Item; + + fn deref(&self) -> &P::Item { + unsafe { &*self.ptr } + } +} + +impl DerefMut for Box

{ + fn deref_mut(&mut self) -> &mut P::Item { + unsafe { &mut *self.ptr } + } +} + +impl core::fmt::Debug for Box

+where + P::Item: core::fmt::Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + ::fmt(self, f) + } +} + +impl core::fmt::Display for Box

+where + P::Item: core::fmt::Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + ::fmt(self, f) + } +} + +impl PartialEq for Box

+where + P::Item: PartialEq, +{ + fn eq(&self, rhs: &Box

) -> bool { + ::eq(self, rhs) + } +} + +impl Eq for Box

where P::Item: Eq {} + +impl PartialOrd for Box

+where + P::Item: PartialOrd, +{ + fn partial_cmp(&self, rhs: &Box

) -> Option { + ::partial_cmp(self, rhs) + } +} + +impl Ord for Box

+where + P::Item: Ord, +{ + fn cmp(&self, rhs: &Box

) -> cmp::Ordering { + ::cmp(self, rhs) + } +} + +impl Hash for Box

+where + P::Item: Hash, +{ + fn hash(&self, state: &mut H) + where + H: Hasher, + { + ::hash(self, state) + } +} + +#[macro_export] +macro_rules! pool { + ($vis:vis $name:ident: [$ty:ty; $size:expr]) => { + $vis struct $name; + impl $crate::Pool for $name { + type Item = $ty; + type Storage = $crate::PoolStorageImpl<$ty, $size>; + fn get() -> &'static Self::Storage { + static POOL: $crate::PoolStorageImpl<$ty, $size> = $crate::PoolStorageImpl::new(); + &POOL + } + } + }; +}