+613
| <div class="title-block" style="text-align: center;" align="center"> | ||
| # `bitvec` <!-- omit in toc --> | ||
| ## Managing Memory Bit by Bit <!-- omit in toc --> | ||
| [![Crate][crate_img]][crate] | ||
| [![Documentation][docs_img]][docs] | ||
| [![License][license_img]][license_file] | ||
| [![Continuous Integration][travis_img]][travis] | ||
| [![Code Coverage][codecov_img]][codecov] | ||
| [![Crate Downloads][downloads_img]][crate] | ||
| [![Crate Size][loc_img]][loc] | ||
| </div> | ||
| `bitvec` permits a program to view memory as bit-addressed, rather than | ||
| byte-addressed. It is a foundation library for `bool`ean collections and | ||
| precise, user-controlled, in-memory layout of data fields and I/O protocol | ||
| buffers. | ||
| # Table of Contents <!-- omit in toc --> | ||
| 1. [Introduction](#introduction) | ||
| 1. [Capabilities](#capabilities) | ||
| 1. [Limitations](#limitations) | ||
| 1. [Usage](#usage) | ||
| 1. [User Stories](#user-stories) | ||
| 1. [Collections of Bits](#collections-of-bits) | ||
| 1. [Bitfield Memory Access](#bitfield-memory-access) | ||
| 1. [Please Just Show Me Some Code](#please-just-show-me-some-code) | ||
| 1. [Feature Flags](#feature-flags) | ||
| 1. [`alloc` Feature](#alloc-feature) | ||
| 1. [`atomic` Feature](#atomic-feature) | ||
| 1. [`serde` Feature](#serde-feature) | ||
| 1. [`std` Feature](#std-feature) | ||
| 1. [API Reference](#api-reference) | ||
| 1. [Implementation Details](#implementation-details) | ||
| 1. [Alias Conditions](#alias-conditions) | ||
| # Introduction | ||
| Computers operate on bytes. Memory is addressed in byte intervals, and processor | ||
| registers are powers of bytes in size. Data that does not evenly fill a byte, or | ||
| a power of a byte, creates inconveniences for the machine and for the | ||
| programmer. | ||
| `bitvec` removes the human-facing inconveniences by modelling memory as if it | ||
| were addressed as individual bits, and registers as if they supported any width. | ||
| If you need to work with data that does not evenly fill one of the fundamental | ||
| register types, or if you need precise control of your in-memory representation | ||
| of a buffer, or if you are merely operating on large collections of `bool`, then | ||
| this library is the best tool available for your use. | ||
| ## Capabilities | ||
| `bitvec` is the only crate in the Rust ecosystem that fits directly into the | ||
| Rust language memory model and APIs. Its most important feature is the | ||
| [`&/mut BitSlice`] reference type, which is a slice of bits without any | ||
| restriction on where in memory it begins or ends. Because it is a reference, it | ||
| can be used in traits whose signatures demand an explicit *reference* type, not | ||
| merely some borrowing handle. | ||
| In addition, `bitvec` implements the register behavior seen in C and Ada | ||
| [bitfield]s by permitting many [`&/mut BitSlice`] regions to be used as if they | ||
| were memory locations into and out of which programmers can move integers. | ||
| Furthermore, `bitvec` implements the entire standard-library sequence API, to | ||
| the point that you can begin using the crate by running a `sed` script and have | ||
| almost no errors. Where `bitvec` is unable to implement an exact port, it | ||
| provides a replacement API with equivalent behavior. | ||
| Lastly, unlike *any* other bit-sequence library the author has encountered, | ||
| `bitvec` is generic over not only the register type used as the underlying | ||
| memory storage (in C bitfields, this is the integer type of the `struct` member), | ||
| but is also generic over the ordering of bit indices within a register. Users | ||
| can select the ordering and register combination that best matches their needs, | ||
| and gain source code that is easily legible, as well as a compiled artifact that | ||
| **just works**, and takes advantage of aggressive compile-time computation and | ||
| codegen optimizations. | ||
| ## Limitations | ||
| The [`&/mut BitSlice`] reference type is implemented with a pointer encoding | ||
| that packs the starting-bit index into the length portion of an ordinary slice | ||
| reference. This costs three bits of the length counter, and requires more | ||
| computation to operate on the pointer than an ordinary slice pointer would | ||
| incur. [`BitSlice`] regions are thus limited to one-eighth the range of a | ||
| `usize` length index. | ||
| While the Rust source code of the library is unable to write the pointer | ||
| encoding as `const fn` (so far), the author has observed that the compiler’s | ||
| existing capabilities for `const`-value propagation eliminate a great deal of | ||
| the pointer encoding’s cost by performing partial or complete work at compile | ||
| time, and create precomputed instruction arguments rather than runtime function | ||
| calls. | ||
| Because the [`&/mut BitSlice`] *reference* uses a unique encoding, the | ||
| `BitSlice` *region* type cannot be used as an argument to any other pointer | ||
| type. You **must** use the container types provided by `bitvec`. If `bitvec` | ||
| does not have a port of the container you want (for example, [`Rc`] and | ||
| [`Arc`]), you must file an issue for future work. | ||
| `bitvec` cannot fully mirror the C++ [`std::bitset<N>`] type until type-level | ||
| integers are more fully stabilized in the Rust compiler. The [`BitArray`] type | ||
| provides the best analogue that Rust can offer. | ||
| # Usage | ||
| **Minimum Supported Rust Version:** `1.47.0` | ||
| `bitvec` does not have a firm MSRV policy. The MSRV is advanced as needed to | ||
| simplify the library’s ongoing development. `bitvec` tracks the evolution of the | ||
| standard library on a best-effort basis. As new behaviors are stabilized on the | ||
| core types it mirrors, `bitvec` will update to match them according to user | ||
| demand or authorial free time. | ||
| To use `bitvec`, depend on it in your Cargo manifest: | ||
| ```toml | ||
| # Cargo.toml | ||
| [dependencies] | ||
| bitvec = "0.20" | ||
| ``` | ||
| and import its prelude into any module that needs it: | ||
| ```rust | ||
| // src/lib.rs | ||
| use bitvec::prelude::*; | ||
| ``` | ||
| The prelude imports all the symbols that the library needs to operate. Almost | ||
| all names begin with `Bit`, which should significantly lower the chances of a | ||
| symbol collision. If you encounter a name collision, or wish greater precision | ||
| over which symbols are imported, consider importing the prelude module itself | ||
| under an alias: | ||
| ```rust | ||
| // src/lib.rs | ||
| use bitvec::prelude as bv; | ||
| ``` | ||
| You can read the [prelude reëxports][prelude] to learn what symbols you need, | ||
| and import them directly rather than using a glob import. | ||
| ## User Stories | ||
| `bitvec` improves upon the Unix tenet of “do[ïng] one thing well” by doing *two* | ||
| things well. By describing memory as a contiguous sequence of individual bits, | ||
| it is able to mirror the standard-library types `[bool]`, `[bool; N]`, | ||
| `Box<[bool]>`, and `Vec<bool>` with types that offer the same API and | ||
| functionality, while storing each bit of the collection in exactly one bit of | ||
| memory, rather than eight. In addition, its implementation of a complete memory | ||
| model allows it to implement the basis of bitfield-style memory access for | ||
| integers, rather than only bits. | ||
| ### Collections of Bits | ||
| > I do not care about what “memory” looks like; I just have some very large | ||
| > collections of `bool`s and I want to use less resident memory! | ||
| > | ||
| > —you, probably | ||
| The fastest way to start using `bitvec` to drive your `bool`ean collections is | ||
| to perform textual find/replace operations: | ||
| - `[bool]` → `BitSlice` | ||
| - `[bool; LEN]` → | ||
| `BitArray<Lsb0, [usize; bitvec::mem::elts::<usize>(LEN)]>` (you probably want | ||
| to compute the new `LEN` yourself) | ||
| - `Box<[bool]>` → `BitBox` | ||
| - `Vec<bool>` → `BitVec` | ||
| If you have errors about missing type parameters, use `<_, _>` or | ||
| `<Lsb0, usize>` as needed until the compiler relents. These are the default type | ||
| arguments and will be the best suited for your target’s performance. | ||
| Almost everything else in your project should continue working. The primary | ||
| exception is that `collection[place] = value;` is not expressible in `bitvec`, | ||
| so any such assignments will need to be changed to | ||
| `collection.set(place, value);` | ||
| > There is an RFC that, if implemented, would make index-access syntax use this | ||
| > method signature! This would allow `[]=`-style assignment, bringing `bitvec` | ||
| > fully in line with the standard-library APIs. | ||
| Any remaining errors should be straightforward to resolve. If they are not, | ||
| please file an issue. | ||
| Once your project compiles again, you will now have smaller heap allocations, | ||
| and possibly faster set analyses. You will also gain set arithmetic and query | ||
| behaviors that the standard library does not have on its `bool`ean collections. | ||
| ### Bitfield Memory Access | ||
| > I am *very* concerned with the precise electrical construction of my memory, | ||
| > and frankly, I’m tired of translating data-sheet cell numbers into shift and | ||
| > mask operations. I don’t want to set one bit at a time, either. I want to be | ||
| > able to write an integer into any section of bits, regardless of what my bus | ||
| > controller thinks is possible. | ||
| > | ||
| > —the crate author, a day before beginning this project | ||
| or | ||
| > i was able to just type bit indices from the datasheet into the rust and it | ||
| > just, works. … itanium is based on 41-bit instruction words and i can just, not | ||
| > care. this is wonderful | ||
| > | ||
| > —a satisfied user | ||
| This project was written specifically to handle the de/construction of I/O | ||
| buffers that are not expressible in ordinary Rust. If you need logic more | ||
| complex than a `#[repr(C)]` attribute on your type definitions and a | ||
| pointer-cast to `*const u8`, then this is the project for you. | ||
| `bitvec` provides two bit-ordering behaviors out of the box: | ||
| - `Lsb0` moves across a register starting at the least significant bit and ending | ||
| at the most significant bit. | ||
| - `Msb0` moves across a register starting at the most significant bit and ending | ||
| at the least significant bit. | ||
| - `LocalBits` is an alias to whichever of those GCC would pick in `struct` | ||
| bitfields. | ||
| Additionally, it allows you to use any of the register types available on your | ||
| target as the memory unit: `u8`, `u16`, `u32`, `u64` (if present), and `usize`. | ||
| While `usize` is the default, you *almost certainly* want to use `u8` for this | ||
| scenario. Almost all protocols are byte-oriented. | ||
| You can read a more thorough explanation, and see tables, of the | ||
| ordering/register combinations in the [Bit Ordering] document. | ||
| ## Please Just Show Me Some Code | ||
| Okay! This snippet provides a whirlwind tour of the library. You can see more | ||
| [examples] in the repository, which showcase more specific goals. | ||
| ```rust | ||
| use bitvec::prelude::*; | ||
| use std::iter::repeat; | ||
| fn main() { | ||
| // You can build a static array, | ||
| let arr = bitarr![Lsb0, u32; 0; 64]; | ||
| // a hidden static slice, | ||
| let slice = bits![mut LocalBits, u16; 0; 10]; | ||
| // or a boxed slice, | ||
| let boxed = bitbox![0; 20]; | ||
| // or a vector, using macros that extend the `vec!` syntax | ||
| let mut bv = bitvec![Msb0, u8; 0, 1, 0, 1]; | ||
| // You can also explicitly borrow existing scalars, | ||
| let data = 0u32; | ||
| let bits = BitSlice::<Lsb0, _>::from_element(&data); | ||
| // or arrays, | ||
| let mut data = [0u8; 3]; | ||
| let bits = BitSlice::<Msb0, _>::from_slice_mut(&mut data[..]); | ||
| // and these are available as shortcut methods: | ||
| let bits = 0u32.view_bits::<Lsb0>(); | ||
| let bits = [0u8; 3].view_bits_mut::<Msb0>(); | ||
| // `BitVec` implements the entire `Vec` API | ||
| bv.reserve(8); | ||
| // Like `Vec<bool>`, it can be extended by any iterator of `bool` or `&bool` | ||
| bv.extend([false; 4].iter()); | ||
| bv.extend([true; 4].iter().copied()); | ||
| // `BitSlice`-owning buffers can be viewed as their raw memory | ||
| assert_eq!( | ||
| bv.as_slice(), | ||
| &[0b0101_0000, 0b1111_0000], | ||
| // ^ index 0 ^ index 11 | ||
| ); | ||
| assert_eq!(bv.len(), 12); | ||
| assert!(bv.capacity() >= 16); | ||
| bv.push(true); | ||
| bv.push(false); | ||
| bv.push(true); | ||
| // `BitSlice` implements indexing | ||
| assert!(bv[12]); | ||
| assert!(!bv[13]); | ||
| assert!(bv[14]); | ||
| assert!(bv.get(15).is_none()); | ||
| // but not in place position | ||
| // bv[12] = false; | ||
| // because it cannot produce `&mut bool`. | ||
| // instead, use `.get_mut()`: | ||
| *bv.get_mut(12).unwrap() = false; | ||
| // or `.set()`: | ||
| bv.set(12, false); | ||
| // range indexing produces subslices | ||
| let last = &bv[12 ..]; | ||
| assert_eq!(last.len(), 3); | ||
| assert!(last.any()); | ||
| for _ in 0 .. 3 { | ||
| assert!(bv.pop().is_some()); | ||
| } | ||
| // `BitSlice` implements set arithmetic against any `bool` iterator | ||
| bv &= repeat(true); | ||
| bv |= repeat(false); | ||
| bv ^= repeat(true); | ||
| bv = !bv; | ||
| // the crate no longer implements integer arithmetic, but `BitSlice` | ||
| // can be used to represent varints in a downstream library. | ||
| // `BitSlice`s are iterators: | ||
| assert_eq!( | ||
| bv.iter().filter(|b| *b).count(), | ||
| 6, | ||
| ); | ||
| // including mutable iteration, though this requires explicit binding: | ||
| for (idx, mut bit) in bv.iter_mut().enumerate() { | ||
| // ^^^ not optional | ||
| *bit ^= idx % 2 == 0; | ||
| } | ||
| // `BitSlice` can also implement bitfield memory behavior: | ||
| bv[1 .. 7].store(0x2Eu8); | ||
| assert_eq!(bv[1 .. 7].load::<u8>(), 0x2E); | ||
| } | ||
| ``` | ||
| As a general rule, you should be able to migrate old code to use the library by | ||
| performing textual replacement of old types with their `bitvec` equivalents, | ||
| such as with `s/Vec<bool>/BitVec/g`, and have the rest of your code using the | ||
| modified values just work. There will be some errors, such as the absence of | ||
| `IndexMut<usize>`, but the crate is built to be as close to drop-in as can | ||
| possibly be expressed. | ||
| The [examples] directory shows how the crate can be used in a variety of | ||
| applications; if it does not contain one relevant to you, please file an issue | ||
| with what you are trying to accomplish (or if you accomplished it already, a | ||
| snippet!) to grow the collection. | ||
| # Feature Flags | ||
| `bitvec` has a few Cargo features that it uses to control its shape. By default, | ||
| its manifest looks like this: | ||
| ```toml | ||
| # Your Cargo.toml | ||
| [dependencies.bitvec] | ||
| version = "0.20" | ||
| features = [ | ||
| "alloc", | ||
| "atomic", | ||
| # "serde", | ||
| "std", | ||
| ] | ||
| ``` | ||
| You can disable the three uncommented features by using the rule | ||
| `default-features = false`, and then reënable the ones you need specifically. | ||
| ## `alloc` Feature | ||
| This feature links `bitvec` against the distribution-provided [`alloc`] crate, | ||
| if your target has one, and enables the [`BitBox`] and [`BitVec`] types. This | ||
| feature is a dependency of the `std` feature, and will always be present when | ||
| building for targets that have [`std`]. If you are building for a `#![no_std]` | ||
| target, you will need to disable the `std` default feature, and may choose to | ||
| reënable the `alloc` feature if your target has an `alloc` library and your | ||
| project specifies an allocator. | ||
| ## `atomic` Feature | ||
| This feature configures whether `bitvec` will attempt to use atomic instructions | ||
| when accessing aliased memory addresses. For a given integer type `T`, if | ||
| `bitvec` is able to use atomic instructions to access it, then | ||
| [`&/mut BitSlice<O, T>`] references are safe to move across thread boundaries. | ||
| If `bitvec` cannot use atomic instructions, either because this feature is | ||
| disabled or because this feature is enabled but the target processor does not | ||
| provide the necessary instructions, then `&/mut BitSlice<O, T>` references lose | ||
| their ability to cross threads. | ||
| `bitvec` uses the [`radium`] project to determine whether atomic instructions | ||
| are available for a given integer type `T` on a target processor. The `"atomic"` | ||
| feature does not **guarantee** atomicity; it can only **attempt** atomicity. If | ||
| `radium` reports that a given integer cannot be accessed atomically on a target, | ||
| then `bitvec` will fall back to non-atomic, non-threadsafe, behavior for that | ||
| integer. | ||
| You may disable this feature to unconditionally use [`Cell`]-based memory access | ||
| to aliased locations, thereby disabling multithreading support in | ||
| [`&/mut BitSlice`] and ensuring that memory access always uses ordinary | ||
| load/store instructions. | ||
| Currently, the targets for which `bitvec` is tested have either no atomic | ||
| instructions at all, or have atomic instructions available for all integer types | ||
| that can be used as the `T` in a [`BitSlice<O, T>`]. `bitvec`’s encoding | ||
| restrictions forbid the use of `u64` on targets with 32-bit processor words, so | ||
| the 32-bit processors that have `AtomicU32` but not `AtomicU64` do not display | ||
| aliasing behavior that varies by integer width. | ||
| ## `serde` Feature | ||
| This feature enables a [`serde::Serialize`] implementation for [`BitSlice`], and | ||
| a full `serde::Serialize`/[`serde::Deserialize`] implementation on [`BitArray`], | ||
| [`BitBox`], and [`BitVec`]. This feature allows you to transport bit collections | ||
| through I/O protocols. | ||
| Note that this behavior is **very** different than using `bitvec` to manage a | ||
| buffer whose *contents* are an I/O protocol message! You may choose to implement | ||
| a `serde::Serializer`/`serde::Deserializer` protocol using `bitvec` to control | ||
| layout of your packets, but the `De`/`Serialize` implementations provided do not | ||
| do this work. They only write a collection into an already-existing transport | ||
| protocol, and are not required to maintain layout representation guarantees. | ||
| In particular, at this time `bitvec` does not transport the bit-ordering or | ||
| memory-element type parameters, so there is no means of ensuring that the | ||
| deserializer is using the same parameter set as the serializer and is thus | ||
| capable of receiving the transported data. | ||
| ## `std` Feature | ||
| This feature links `bitvec` against the distribution-provided [`std`] crate, if | ||
| your target has one. The only additional features it provides that are not | ||
| present in [`alloc`] are implementations of [`io::Read`] and [`io::Write`] on | ||
| data structures that match `Read` and `Write` types in `std`, for bit orderings | ||
| that have [`BitField`] trait implementations. | ||
| # API Reference | ||
| The complete API reference can be found on [docs.rs], and will not be duplicated | ||
| here. As a summary: | ||
| The [`BitSlice`] type describes a region of memory viewed in bit-addressed | ||
| precision. It is parameterized by two types, a [`BitOrder`] translation of | ||
| indices to positions within a register type, and a [`BitStore`] register type. | ||
| It is a region type, and cannot be held as an immediate. It must be held by | ||
| reference, `&BitSlice<O, T>` or `&mut BitSlice<O, T>`, or through one of the | ||
| container types provided by `bitvec`. It cannot, ever, be used as a type | ||
| parameter in containers not provided by this crate. | ||
| The [`BitArray`] type describes a block of contiguous memory, which can be | ||
| backed by a scalar or an array of scalars, as a `BitSlice` region. The Rust | ||
| type-level-integer language implementation is not yet sufficient to correctly | ||
| port the C++ `std::bitset<N>` type, so this type is instead parameterized over | ||
| the backing memory type, rather than a number of bits. Hopefully, this will | ||
| change in the future to permit `<Order, Store, const Bits>` instead. | ||
| The [`BitBox`] and [`BitVec`] types are heap-allocated owning buffers, | ||
| corresponding to `Box<[bool]>` and `Vec<bool>`, respectively. They defer to | ||
| `BitSlice` for data manipulation, and their only inherent behavior is | ||
| manipulation of the allocated block. | ||
| Each data type has a constructor macro: [`bits!`] for `BitSlice`, [`bitarr!]` | ||
| for `BitArray`, [`bitbox!`] for `BitBox`, and [`bitvec!`] for `BitVec`. These | ||
| macros implement a superset of the `vec!` macro’s argument grammar, and enable | ||
| the compile-time construction of `BitSlice` buffers. `bitbox!` and `bitvec!` | ||
| copy their precomputed buffers into heap allocations at runtime. | ||
| The [`BitField`] trait describes how a `BitSlice` region can be used for value | ||
| storage. It is implemented for `BitSlice<Lsb0, _>` and `BitSlice<Msb0, _>`, | ||
| enabling those slices to act as memory stores for any unsigned integral value. | ||
| The [`BitOrder`] trait provides translations from semantic indices that appear | ||
| in user code to the actual shift-and-mask instructions used to operate on | ||
| memory. As this trait has very strict requirements for implementations that | ||
| cannot (yet) be made into compiler errors, it is marked `unsafe`. | ||
| Implementations other than the provided [`Lsb0`] and [`Msb0`] are permitted, but | ||
| will have niche applicability and, likely, reduced performance. | ||
| The [`BitStore`] trait describes memory elements, and their behavior in CPU | ||
| registers and during load/store instructions. It is implemented on the unsigned | ||
| integers not wider than a processor word, their `Cell<>` wrappers, and their | ||
| `Atomic` variants. It cannot be implemented outside `bitvec`. | ||
| The [`BitView`], [`AsBits<T>`], and [`AsBitsMut<T>`] traits allow a type to | ||
| define how it can be viewed as a [`BitSlice`]. Default implementations are | ||
| provided for integers and integer arrays, and can be added for user types. | ||
| The `domain` module implements the crate’s internal memory model, and performs | ||
| the work of managing alias detection and selecting the appropriate un/aliased | ||
| memory behaviors. The enums in it are part of the primary API, and can be | ||
| constructed from [`BitSlice`]s in order to enable precise memory accesses. | ||
| ## Implementation Details | ||
| In addition to the API surface for general use, `bitvec` exposes some APIs that | ||
| are useful for developing the crate itself, or extensions to it. | ||
| The `devel` module contains snippets of type manipulation or value checking used | ||
| in the crate internals. These functions are not part of the public API, but are | ||
| pieces of logic that occur often enough in crate internals to be worth naming, | ||
| and are likely to be useful in extension code as well. | ||
| The `index` module contains typed indices into register elements. Implementors | ||
| of the `BitOrder` trait operate on the types here in order to plug into the rest | ||
| of the crate system. This module also contains register types needed to interact | ||
| with the `access` module, if you want to use the memory interface system | ||
| separately from the crate’s data structures. | ||
| The `mem` module contains logic for operating on integers in memory. It is an | ||
| implementation detail of the memory modeling system. | ||
| The `pointer` module implements the pointer encoding used to drive the | ||
| `&BitSlice` reference type. It is explicitly **not** exposed outside the crate, | ||
| and is not planned to be stabilized as an external interface. If you have a use | ||
| case for it, please file an issue. | ||
| # Alias Conditions | ||
| `bitvec` operates on the principle that each bit is an individually-addressed | ||
| element of memory. This is, of course, untrue in hardware, and so `bitvec` must | ||
| be aware of the underlying memory region and how the bus drives `bitvec`’s | ||
| operation. | ||
| `bitvec` structures may only be constructed over raw integers. Once constructed, | ||
| a `&mut BitSlice` can be split into multiple subslices that do not overlap in | ||
| bits, but do overlap in memory elements on the bus. In order to remain correct | ||
| in the Rust memory model and in the generated instructions, these split slices | ||
| are marked as aliased, and switch over to using coördinated types capable of | ||
| handling multiple handles with write capability to the same element. By default, | ||
| these types are atomic, however, as discussed above, they can fall back to | ||
| `Cell`s instead. | ||
| `bitvec` is capable of performing pointer analysis to determine which elements | ||
| in a slice region are known to be aliased and which are not. This analysis | ||
| depends on the rule that `&`/`&mut` exclusion *and modification* rules apply to | ||
| the entire `BitSlice` region, but the [`UnsafeCell`] type sidesteps this: shared | ||
| references are still capable of modifying the memory regions that may be viewed | ||
| by shared references that do *not* expect volatility. | ||
| Instead, `bitvec` uses wrapper types over atoms and cells that disallow mutation | ||
| of the underlying memory except through `&mut` exclusive references. These | ||
| wrapper types retain the volatility properties of their wrapped types, and so, | ||
| for instance, the wrapped atomic will still perform an atomic load from memory | ||
| on each access. The only restriction needed is that these types cannot be used | ||
| to write into memory that has any possibility of being viewed without a | ||
| synchronization control. | ||
| `bitvec` has no plans to support shared-mutable `BitSlice` regions. | ||
| <!-- Badges --> | ||
| [codecov]: https://codecov.io/gh/myrrlyn/bitvec "Code Coverage" | ||
| [codecov_img]: https://img.shields.io/codecov/c/github/myrrlyn/bitvec.svg?logo=codecov "Code Coverage Display" | ||
| [crate]: https://crates.io/crates/bitvec "Crate Link" | ||
| [crate_img]: https://img.shields.io/crates/v/bitvec.svg?logo=rust "Crate Page" | ||
| [docs]: https://docs.rs/bitvec "Documentation" | ||
| [docs_img]: https://docs.rs/bitvec/badge.svg "Documentation Display" | ||
| [downloads_img]: https://img.shields.io/crates/dv/bitvec.svg?logo=rust "Crate Downloads" | ||
| [license_file]: https://github.com/myrrlyn/bitvec/blob/master/LICENSE.txt "License File" | ||
| [license_img]: https://img.shields.io/crates/l/bitvec.svg "License Display" | ||
| [loc]: https://github.com/myrrlyn/bitvec "Repository" | ||
| [loc_img]: https://tokei.rs/b1/github/myrrlyn/bitvec?category=code "Repository Size" | ||
| [travis]: https://travis-ci.org/myrrlyn/bitvec "Travis CI" | ||
| [travis_img]: https://img.shields.io/travis/myrrlyn/bitvec.svg?logo=travis "Travis CI Display" | ||
| <!-- Documentation --> | ||
| [`Arc`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html "Arc API reference" | ||
| [`AsBits<T>`]: https://docs.rs/bitvec/latest/bitvec/view/trait.AsBits.html "AsBits API reference" | ||
| [`AsBitsMut<T>`]: https://docs.rs/bitvec/latest/bitvec/view/trait.AsBitsMut.html "AsBitsMut API reference" | ||
| [`AtomicU8`]: https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU8.html "AtomicU8 API reference" | ||
| [`AtomicU64`]: https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU64.html "AtomicU64 API reference" | ||
| [`AtomicUsize`]: https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html "AtomicUsize API reference" | ||
| [`BitArray`]: https://docs.rs/bitvec/latest/bitvec/array/struct.BitArray.html "BitArray API reference" | ||
| [`BitBox`]: https://docs.rs/bitvec/latest/bitvec/boxed/struct.BitBox.html "BitBox API reference" | ||
| [`BitField`]: https://docs.rs/bitvec/latest/bitvec/fields/trait.BitField.html "BitField API reference" | ||
| [`BitOrder`]: https://docs.rs/bitvec/latest/bitvec/order/trait.BitOrder.html "BitOrder API reference" | ||
| [`BitSlice`]: https://docs.rs/bitvec/latest/bitvec/slice/struct.BitSlice.html "BitSlice API reference" | ||
| [`BitSlice<O, T>`]: https://docs.rs/bitvec/latest/bitvec/slice/struct.BitSlice.html "BitSlice API reference" | ||
| [`BitSlice::split_at_mut`]: https://docs.rs/bitvec/latest/bitvec/slice/struct.BitSlice.html#method.split_at_mut "BitSlice::split_at_mut API reference" | ||
| [`BitStore`]: https://docs.rs/bitvec/latest/bitvec/store/trait.BitStore.html "BitStore API reference" | ||
| [`BitVec`]: https://docs.rs/bitvec/latest/bitvec/vec/struct.BitVec.html "BitVec API reference" | ||
| [`BitView`]: https://docs.rs/bitvec/latest/bitvec/view/trait.BitView.html "BitView API reference" | ||
| [`Cell`]: https://doc.rust-lang.org/stable/core/cell/struct.Cell.html "Cell API reference" | ||
| [`Lsb0`]: https://docs.rs/bitvec/latest/bitvec/order/struct.Lsb0.html "Lsb0 API reference" | ||
| [`Msb0`]: https://docs.rs/bitvec/latest/bitvec/order/struct.Msb0.html "Msb0 API reference" | ||
| [`Rc`]: https://doc.rust-lang.org/stable/alloc/rc/struct.Rc.html "Rc API reference" | ||
| [`UnsafeCell`]: https://doc.rust-lang.org/stable/core/cell/struct.UnsafeCell.html "UnsafeCell API reference" | ||
| [`alloc`]: https://doc.rust-lang.org/stable/alloc "alloc API reference" | ||
| [`bitarr!`]: https://docs.rs/bitvec/latest/bitvec/macro.bitarr.html "bitarr! API reference" | ||
| [`bitbox!`]: https://docs.rs/bitvec/latest/bitvec/macro.bitbox.html "bitbox! API reference" | ||
| [`bits!`]: https://docs.rs/bitvec/latest/bitvec/macro.bits.html "bits! API reference" | ||
| [`bitvec!`]: https://docs.rs/bitvec/latest/bitvec/macro.bitvec.html "bitvec! API reference" | ||
| [`domain`]: https://docs.rs/bitvec/latest/bitvec/domain "Domain module API reference" | ||
| [`io::Read`]: https://doc.rust-lang.org/stable/std/io/trait.Read.html "Read API reference" | ||
| [`io::Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html "Write API reference" | ||
| [`serde::Deserialize`]: https://docs.rs/serde/latest/serde/de/trait.Deserialize.html "Deserialize API reference" | ||
| [`serde::Serialize`]: https://docs.rs/serde/latest/serde/ser/trait.Serialize.html "Serialize API reference" | ||
| [`std`]: https://doc.rust-lang.org/stable/std "std API reference" | ||
| [`&/mut BitSlice`]: https://docs.rs/bitvec/latest/bitvec/slice/struct.BitSlice.html "BitSlice API reference" | ||
| [Bit Ordering]: https://github.com/myrrlyn/bitvec/blob/HEAD/develop/book/bit-ordering.md | ||
| [docs.rs]: https://docs.rs/bitvec/latest/bitvec "crate API reference" | ||
| [examples]: https://github.com/myrrlyn/bitvec/blob/HEAD/examples | ||
| [macro]: https://docs.rs/bitvec/latest/bitvec/#macros | ||
| [prelude]: https://docs.rs/bitvec/latest/bitvec/prelude | ||
| <!-- External References --> | ||
| [`radium`]: https://crates.io/crates/radium | ||
| [`std::bitset<N>`]: https://en.cppreference.com/w/cpp/utility/bitset | ||
| [bitfield]: https://en.cppreference.com/w/cpp/language/bit_field "C++ bitfields" |
| { | ||
| "git": { | ||
| "sha1": "18d91b6133bd1b44b4595df7981a0e83d04ac298" | ||
| "sha1": "678b67921f04be93e3f62db3ba1ff8efe9a09d7e" | ||
| } | ||
| } |
+253
-47
@@ -9,7 +9,13 @@ /*! Benchmarks for `BitSlice::copy_from_slice`. | ||
| #![feature(maybe_uninit_uninit_array, maybe_uninit_slice)] | ||
| use std::mem::MaybeUninit; | ||
| use bitvec::{ | ||
| mem::BitMemory, | ||
| mem::{ | ||
| elts, | ||
| BitMemory, | ||
| }, | ||
| prelude::*, | ||
| }; | ||
| use criterion::{ | ||
@@ -20,61 +26,261 @@ criterion_group, | ||
| Criterion, | ||
| SamplingMode, | ||
| Throughput, | ||
| }; | ||
| use tap::tap::Tap; | ||
| // One kibibit | ||
| const FACTOR: usize = 1024; | ||
| // One kibibyte | ||
| const KIBIBYTE: usize = 1024; | ||
| // Some number of kibibytes | ||
| const FACTOR: usize = 1 * KIBIBYTE; | ||
| // Scalars applied to FACTOR to get a range of action | ||
| const SCALARS: &[usize] = &[1, 2, 4, 8, 16, 24, 32, 40, 52, 64]; | ||
| // The maximum number of bits in a memory region. | ||
| const MAX_BITS: usize = 64 * FACTOR * 8; | ||
| fn make_slots<T, const LEN: usize>() | ||
| -> ([MaybeUninit<T>; LEN], [MaybeUninit<T>; LEN]) | ||
| where T: BitStore { | ||
| ( | ||
| MaybeUninit::<T>::uninit_array::<LEN>(), | ||
| MaybeUninit::<T>::uninit_array::<LEN>(), | ||
| ) | ||
| } | ||
| fn view_slots<'a, 'b, T>( | ||
| src: &'a [MaybeUninit<T>], | ||
| dst: &'b mut [MaybeUninit<T>], | ||
| ) -> (&'a [T], &'b mut [T]) | ||
| where | ||
| T: BitStore, | ||
| { | ||
| unsafe { | ||
| ( | ||
| MaybeUninit::slice_assume_init_ref(src), | ||
| MaybeUninit::slice_assume_init_mut(dst), | ||
| ) | ||
| } | ||
| } | ||
| pub fn benchmarks(crit: &mut Criterion) { | ||
| fn steps() -> impl Iterator<Item = (BenchmarkId, usize, Throughput)> { | ||
| [1, 2, 4, 8, 16, 24, 32, 40, 48, 56, 64] | ||
| .iter() | ||
| .copied() | ||
| .map(|n| { | ||
| ( | ||
| BenchmarkId::from_parameter(n), | ||
| n * FACTOR, | ||
| Throughput::Elements( | ||
| (n * FACTOR / <usize as BitMemory>::BITS as usize) | ||
| as u64, | ||
| ), | ||
| ) | ||
| fn steps() | ||
| -> impl Iterator<Item = (impl Fn(&'static str) -> BenchmarkId, usize, Throughput)> | ||
| { | ||
| SCALARS.iter().map(|&n| { | ||
| ( | ||
| move |name| BenchmarkId::new(name, n), | ||
| n * FACTOR * <u8 as BitMemory>::BITS as usize, | ||
| Throughput::Bytes((n * FACTOR) as u64), | ||
| ) | ||
| }) | ||
| } | ||
| let (src_words, mut dst_words) = | ||
| make_slots::<usize, { elts::<usize>(MAX_BITS) }>(); | ||
| let (src_bytes, mut dst_bytes) = | ||
| make_slots::<u8, { elts::<u8>(MAX_BITS) }>(); | ||
| let (src_words, dst_words) = view_slots(&src_words, &mut dst_words); | ||
| let (src_bytes, dst_bytes) = view_slots(&src_bytes, &mut dst_bytes); | ||
| macro_rules! mkgrp { | ||
| ($crit:ident, $name:literal) => { | ||
| (&mut *$crit).benchmark_group($name).tap_mut(|grp| { | ||
| grp.sampling_mode(SamplingMode::Flat).sample_size(2000); | ||
| }) | ||
| }; | ||
| } | ||
| fn mkgroup< | ||
| O: BitOrder, | ||
| F: FnMut(usize, &mut BitSlice, &BitSlice<O, usize>), | ||
| >( | ||
| name: &'static str, | ||
| crit: &mut Criterion, | ||
| mut func: F, | ||
| ) { | ||
| let mut group = crit.benchmark_group(name); | ||
| for (id, len, elems) in steps() { | ||
| let mut dst = BitVec::repeat(false, len); | ||
| let src = BitVec::<O, usize>::repeat(true, len); | ||
| let mut group = mkgrp!(crit, "Element-wise"); | ||
| for (id, bits, thrpt) in steps() { | ||
| group.throughput(thrpt); | ||
| let words = bits / <usize as BitMemory>::BITS as usize; | ||
| let bytes = bits / <u8 as BitMemory>::BITS as usize; | ||
| let dst = dst.as_mut_bitslice(); | ||
| let src = src.as_bitslice(); | ||
| group.throughput(elems); | ||
| group.bench_function(id, |b| b.iter(|| func(len, dst, src))); | ||
| } | ||
| group.finish(); | ||
| let (src_words, dst_words) = | ||
| (&src_words[.. words], &mut dst_words[.. words]); | ||
| let (src_bytes, dst_bytes) = | ||
| (&src_bytes[.. bytes], &mut dst_bytes[.. bytes]); | ||
| // Use the builtin memcpy to run the slices in bulk. This ought to be a | ||
| // lower bound on execution time. | ||
| group.bench_function(id("words_plain"), |b| { | ||
| let (src, dst) = (src_words, &mut *dst_words); | ||
| b.iter(|| dst.copy_from_slice(src)) | ||
| }); | ||
| group.bench_function(id("bytes_plain"), |b| { | ||
| let (src, dst) = (src_bytes, &mut *dst_bytes); | ||
| b.iter(|| dst.copy_from_slice(src)) | ||
| }); | ||
| group.bench_function(id("words_manual"), |b| { | ||
| let (src, dst) = (src_words, &mut *dst_words); | ||
| b.iter(|| { | ||
| for (from, to) in src.iter().zip(dst.iter_mut()) { | ||
| *to = *from; | ||
| } | ||
| }) | ||
| }); | ||
| group.bench_function(id("bytes_manual"), |b| { | ||
| let (src, dst) = (src_bytes, &mut *dst_bytes); | ||
| b.iter(|| { | ||
| for (from, to) in src.iter().zip(dst.iter_mut()) { | ||
| *to = *from; | ||
| } | ||
| }) | ||
| }); | ||
| } | ||
| group.finish(); | ||
| mkgroup::<Lsb0, _>("memcpy", crit, |len, dst, src| { | ||
| dst[10 .. len - 10].copy_from_bitslice(&src[10 .. len - 10]); | ||
| }); | ||
| let mut group = mkgrp!(crit, "Bit-wise accelerated"); | ||
| for (id, bits, thrpt) in steps() { | ||
| group.throughput(thrpt); | ||
| let words = bits / <usize as BitMemory>::BITS as usize; | ||
| let bytes = bits / <u8 as BitMemory>::BITS as usize; | ||
| mkgroup::<Lsb0, _>("load_store", crit, |len, dst, src| { | ||
| dst[10 ..].copy_from_bitslice(&src[.. len - 10]); | ||
| }); | ||
| let (src_words, dst_words) = | ||
| (&src_words[.. words], &mut dst_words[.. words]); | ||
| let (src_bytes, dst_bytes) = | ||
| (&src_bytes[.. bytes], &mut dst_bytes[.. bytes]); | ||
| mkgroup::<Lsb0, _>("bitwise", crit, |_, dst, src| { | ||
| dst.clone_from_bitslice(src) | ||
| }); | ||
| // Ideal bitwise memcpy: no edges, same typarams, fully aligned. | ||
| mkgroup::<Msb0, _>("mismatch", crit, |_, dst, src| { | ||
| dst.clone_from_bitslice(src) | ||
| }); | ||
| group.bench_function(id("bits_words_plain"), |b| { | ||
| let (src, dst) = ( | ||
| src_words.view_bits::<Lsb0>(), | ||
| dst_words.view_bits_mut::<Lsb0>(), | ||
| ); | ||
| b.iter(|| dst.copy_from_bitslice(src)); | ||
| }); | ||
| group.bench_function(id("bits_bytes_plain"), |b| { | ||
| let (src, dst) = ( | ||
| src_bytes.view_bits::<Lsb0>(), | ||
| dst_bytes.view_bits_mut::<Lsb0>(), | ||
| ); | ||
| b.iter(|| dst.copy_from_bitslice(src)); | ||
| }); | ||
| // Same typarams, fully aligned, with fuzzed edges. | ||
| group.bench_function(id("bits_words_edges"), |b| { | ||
| let src = src_words.view_bits::<Lsb0>(); | ||
| let len = src.len(); | ||
| let (src, dst) = ( | ||
| &src[10 .. len - 10], | ||
| &mut dst_words.view_bits_mut::<Lsb0>()[10 .. len - 10], | ||
| ); | ||
| b.iter(|| dst.copy_from_bitslice(src)); | ||
| }); | ||
| group.bench_function(id("bits_bytes_edges"), |b| { | ||
| let src = src_bytes.view_bits::<Lsb0>(); | ||
| let len = src.len(); | ||
| let (src, dst) = ( | ||
| &src[10 .. len - 10], | ||
| &mut dst_bytes.view_bits_mut::<Lsb0>()[10 .. len - 10], | ||
| ); | ||
| b.iter(|| dst.copy_from_bitslice(src)); | ||
| }); | ||
| // Same typarams, misaligned. | ||
| group.bench_function(id("bits_words_misalign"), |b| { | ||
| let src = &src_words.view_bits::<Lsb0>()[10 ..]; | ||
| let dst = &mut dst_words.view_bits_mut::<Lsb0>()[.. src.len()]; | ||
| b.iter(|| dst.copy_from_bitslice(src)); | ||
| }); | ||
| group.bench_function(id("bits_bytes_misalign"), |b| { | ||
| let src = &src_bytes.view_bits::<Lsb0>()[10 ..]; | ||
| let dst = &mut dst_bytes.view_bits_mut::<Lsb0>()[.. src.len()]; | ||
| b.iter(|| dst.copy_from_bitslice(src)); | ||
| }); | ||
| } | ||
| group.finish(); | ||
| let mut group = mkgrp!(crit, "Bit-wise crawl"); | ||
| for (id, bits, thrpt) in steps() { | ||
| group.throughput(thrpt); | ||
| let words = bits / <usize as BitMemory>::BITS as usize; | ||
| let bytes = bits / <u8 as BitMemory>::BITS as usize; | ||
| let (src_words, dst_words) = | ||
| (&src_words[.. words], &mut dst_words[.. words]); | ||
| let (src_bytes, dst_bytes) = | ||
| (&src_bytes[.. bytes], &mut dst_bytes[.. bytes]); | ||
| // Mismatched type parameters | ||
| group.bench_function(id("bits_words_mismatched"), |b| { | ||
| let (src, dst) = ( | ||
| src_words.view_bits::<Msb0>(), | ||
| dst_words.view_bits_mut::<Lsb0>(), | ||
| ); | ||
| b.iter(|| dst.clone_from_bitslice(src)); | ||
| }); | ||
| group.bench_function(id("bits_bytes_mismatched"), |b| { | ||
| let (src, dst) = ( | ||
| src_bytes.view_bits::<Msb0>(), | ||
| dst_bytes.view_bits_mut::<Lsb0>(), | ||
| ); | ||
| b.iter(|| dst.clone_from_bitslice(src)); | ||
| }); | ||
| // Crawl each bit individually. This ought to be an upper bound on | ||
| // execution time. | ||
| group.bench_function(id("bitwise_words"), |b| { | ||
| let (src, dst) = ( | ||
| src_words.view_bits::<Lsb0>(), | ||
| dst_words.view_bits_mut::<Lsb0>(), | ||
| ); | ||
| b.iter(|| unsafe { | ||
| for (from, to) in | ||
| src.as_bitptr_range().zip(dst.as_mut_bitptr_range()) | ||
| { | ||
| to.write(from.read()); | ||
| } | ||
| }) | ||
| }); | ||
| group.bench_function(id("bitwise_bytes"), |b| { | ||
| let (src, dst) = ( | ||
| src_bytes.view_bits::<Lsb0>(), | ||
| dst_bytes.view_bits_mut::<Lsb0>(), | ||
| ); | ||
| b.iter(|| unsafe { | ||
| for (from, to) in | ||
| src.as_bitptr_range().zip(dst.as_mut_bitptr_range()) | ||
| { | ||
| to.write(from.read()); | ||
| } | ||
| }) | ||
| }); | ||
| group.bench_function(id("bitwise_words_mismatch"), |b| { | ||
| let (src, dst) = ( | ||
| src_words.view_bits::<Lsb0>(), | ||
| dst_words.view_bits_mut::<Msb0>(), | ||
| ); | ||
| b.iter(|| unsafe { | ||
| for (from, to) in | ||
| src.as_bitptr_range().zip(dst.as_mut_bitptr_range()) | ||
| { | ||
| to.write(from.read()); | ||
| } | ||
| }) | ||
| }); | ||
| group.bench_function(id("bitwise_bytes_mismatch"), |b| { | ||
| let (src, dst) = ( | ||
| src_bytes.view_bits::<Msb0>(), | ||
| dst_bytes.view_bits_mut::<Lsb0>(), | ||
| ); | ||
| b.iter(|| unsafe { | ||
| for (from, to) in | ||
| src.as_bitptr_range().zip(dst.as_mut_bitptr_range()) | ||
| { | ||
| to.write(from.read()); | ||
| } | ||
| }) | ||
| }); | ||
| } | ||
| } | ||
@@ -81,0 +287,0 @@ |
+38
-31
@@ -22,5 +22,5 @@ # This file is automatically @generated by Cargo. | ||
| name = "bincode" | ||
| version = "1.3.2" | ||
| version = "1.3.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772" | ||
| checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" | ||
| dependencies = [ | ||
@@ -39,3 +39,3 @@ "byteorder", | ||
| name = "bitvec" | ||
| version = "0.20.4" | ||
| version = "0.21.0" | ||
| dependencies = [ | ||
@@ -68,11 +68,11 @@ "bincode", | ||
| name = "bumpalo" | ||
| version = "3.6.1" | ||
| version = "3.6.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" | ||
| checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" | ||
| [[package]] | ||
| name = "byteorder" | ||
| version = "1.3.4" | ||
| version = "1.4.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" | ||
| checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" | ||
@@ -106,2 +106,8 @@ [[package]] | ||
| [[package]] | ||
| name = "const_fn" | ||
| version = "0.4.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" | ||
| [[package]] | ||
| name = "criterion" | ||
@@ -165,7 +171,8 @@ version = "0.3.4" | ||
| name = "crossbeam-epoch" | ||
| version = "0.9.3" | ||
| version = "0.9.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" | ||
| checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "const_fn", | ||
| "crossbeam-utils", | ||
@@ -179,5 +186,5 @@ "lazy_static", | ||
| name = "crossbeam-utils" | ||
| version = "0.8.3" | ||
| version = "0.8.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" | ||
| checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" | ||
| dependencies = [ | ||
@@ -219,5 +226,5 @@ "autocfg", | ||
| name = "funty" | ||
| version = "1.1.0" | ||
| version = "1.2.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" | ||
| checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" | ||
@@ -265,5 +272,5 @@ [[package]] | ||
| name = "js-sys" | ||
| version = "0.3.48" | ||
| version = "0.3.47" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" | ||
| checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" | ||
| dependencies = [ | ||
@@ -281,5 +288,5 @@ "wasm-bindgen", | ||
| name = "libc" | ||
| version = "0.2.87" | ||
| version = "0.2.86" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" | ||
| checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" | ||
@@ -562,5 +569,5 @@ [[package]] | ||
| name = "tinytemplate" | ||
| version = "1.2.1" | ||
| version = "1.2.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" | ||
| checksum = "a2ada8616fad06a2d0c455adc530de4ef57605a8120cc65da9653e0e9623ca74" | ||
| dependencies = [ | ||
@@ -596,5 +603,5 @@ "serde", | ||
| name = "wasm-bindgen" | ||
| version = "0.2.71" | ||
| version = "0.2.70" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" | ||
| checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" | ||
| dependencies = [ | ||
@@ -607,5 +614,5 @@ "cfg-if", | ||
| name = "wasm-bindgen-backend" | ||
| version = "0.2.71" | ||
| version = "0.2.70" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" | ||
| checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" | ||
| dependencies = [ | ||
@@ -623,5 +630,5 @@ "bumpalo", | ||
| name = "wasm-bindgen-macro" | ||
| version = "0.2.71" | ||
| version = "0.2.70" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" | ||
| checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" | ||
| dependencies = [ | ||
@@ -634,5 +641,5 @@ "quote", | ||
| name = "wasm-bindgen-macro-support" | ||
| version = "0.2.71" | ||
| version = "0.2.70" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" | ||
| checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" | ||
| dependencies = [ | ||
@@ -648,11 +655,11 @@ "proc-macro2", | ||
| name = "wasm-bindgen-shared" | ||
| version = "0.2.71" | ||
| version = "0.2.70" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" | ||
| checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" | ||
| [[package]] | ||
| name = "web-sys" | ||
| version = "0.3.48" | ||
| version = "0.3.47" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" | ||
| checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" | ||
| dependencies = [ | ||
@@ -659,0 +666,0 @@ "js-sys", |
+4
-4
@@ -16,5 +16,5 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "bitvec" | ||
| version = "0.20.4" | ||
| version = "0.21.0" | ||
| authors = ["myrrlyn <self@myrrlyn.dev>"] | ||
| include = ["Cargo.toml", "LICENSE.txt", "src/**/*.rs", "benches/*.rs"] | ||
| include = ["Cargo.toml", "LICENSE.txt", "README.md", "src/**/*.rs", "benches/*.rs"] | ||
| description = "A crate for manipulating memory, bit by bit" | ||
@@ -35,7 +35,7 @@ homepage = "https://myrrlyn.net/crates/bitvec" | ||
| [dependencies.funty] | ||
| version = "~1.1" | ||
| version = "1" | ||
| default-features = false | ||
| [dependencies.radium] | ||
| version = "0.6.1" | ||
| version = "0.6" | ||
@@ -42,0 +42,0 @@ [dependencies.serde] |
+4
-4
@@ -22,2 +22,6 @@ /*! Memory access guards. | ||
| use core::sync::atomic; | ||
| use radium::Radium; | ||
| use crate::{ | ||
@@ -32,6 +36,2 @@ index::{ | ||
| use core::sync::atomic; | ||
| use radium::Radium; | ||
| /** Abstracts over the instructions used when accessing a memory location. | ||
@@ -38,0 +38,0 @@ |
+7
-7
@@ -18,2 +18,8 @@ /*! A statically-allocated, fixed-size, buffer containing a [`BitSlice`] region. | ||
| use core::{ | ||
| marker::PhantomData, | ||
| mem::MaybeUninit, | ||
| slice, | ||
| }; | ||
| use crate::{ | ||
@@ -28,8 +34,2 @@ order::{ | ||
| use core::{ | ||
| marker::PhantomData, | ||
| mem::MaybeUninit, | ||
| slice, | ||
| }; | ||
| /* Note on C++ `std::bitset<N>` compatibility: | ||
@@ -105,3 +105,3 @@ | ||
| /// // creates a type declaration. | ||
| /// fields: bitarr!(for 20, in Msb0, u8), | ||
| /// fields: BitArr!(for 20, in Msb0, u8), | ||
| /// } | ||
@@ -108,0 +108,0 @@ /// |
| //! Array iteration. | ||
| use crate::{ | ||
| array::BitArray, | ||
| mutability::Const, | ||
| order::BitOrder, | ||
| ptr::BitPtr, | ||
| slice::BitSlice, | ||
| view::BitView, | ||
| }; | ||
| use core::{ | ||
@@ -24,2 +15,11 @@ fmt::{ | ||
| use crate::{ | ||
| array::BitArray, | ||
| mutability::Const, | ||
| order::BitOrder, | ||
| ptr::BitPtr, | ||
| slice::BitSlice, | ||
| view::BitView, | ||
| }; | ||
| /** A by-value [bit-array] iterator. | ||
@@ -26,0 +26,0 @@ |
+8
-8
| //! Port of the `[T; N]` operator implementations. | ||
| use crate::{ | ||
| array::BitArray, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| use core::ops::{ | ||
@@ -25,2 +17,10 @@ BitAnd, | ||
| use crate::{ | ||
| array::BitArray, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| impl<O, V, Rhs> BitAnd<Rhs> for BitArray<O, V> | ||
@@ -27,0 +27,0 @@ where |
@@ -5,6 +5,6 @@ //! Unit tests for the `array` module. | ||
| use tap::conv::TryConv; | ||
| use crate::prelude::*; | ||
| use tap::conv::TryConv; | ||
| #[test] | ||
@@ -11,0 +11,0 @@ fn create_arrays() { |
+16
-15
| //! Non-operator trait implementations. | ||
| use crate::{ | ||
| array::{ | ||
| iter::IntoIter, | ||
| BitArray, | ||
| }, | ||
| index::BitIdx, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| use core::{ | ||
@@ -38,2 +26,14 @@ borrow::{ | ||
| use crate::{ | ||
| array::{ | ||
| iter::IntoIter, | ||
| BitArray, | ||
| }, | ||
| index::BitIdx, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| #[cfg(not(tarpaulin_include))] | ||
@@ -98,5 +98,6 @@ impl<O, V> Borrow<BitSlice<O, V::Store>> for BitArray<O, V> | ||
| impl<O, V, T> PartialEq<BitArray<O, V>> for BitSlice<O, T> | ||
| impl<O1, O2, V, T> PartialEq<BitArray<O2, V>> for BitSlice<O1, T> | ||
| where | ||
| O: BitOrder, | ||
| O1: BitOrder, | ||
| O2: BitOrder, | ||
| V: BitView, | ||
@@ -106,3 +107,3 @@ T: BitStore, | ||
| #[inline] | ||
| fn eq(&self, other: &BitArray<O, V>) -> bool { | ||
| fn eq(&self, other: &BitArray<O2, V>) -> bool { | ||
| self == other.as_bitslice() | ||
@@ -109,0 +110,0 @@ } |
+10
-11
@@ -32,5 +32,13 @@ /*! A dynamically-allocated, fixed-size, buffer containing a [`BitSlice`] | ||
| use alloc::boxed::Box; | ||
| use core::{ | ||
| mem::ManuallyDrop, | ||
| slice, | ||
| }; | ||
| use funty::IsNumber; | ||
| use tap::pipe::Pipe; | ||
| use crate::{ | ||
| index::BitIdx, | ||
| mem::BitMemory, | ||
| mutability::Mut, | ||
@@ -50,11 +58,2 @@ order::{ | ||
| use alloc::boxed::Box; | ||
| use core::{ | ||
| mem::ManuallyDrop, | ||
| slice, | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| /** A frozen heap-allocated buffer of individual bits. | ||
@@ -157,3 +156,3 @@ | ||
| /// assert_eq!(bb, bits[2 ..]); | ||
| /// assert_eq!(bb.as_slice(), bits.as_slice()); | ||
| /// assert_eq!(bb.as_slice(), bits.as_raw_slice()); | ||
| /// ``` | ||
@@ -160,0 +159,0 @@ /// |
+8
-8
| //! Port of the `Box<[T]>` inherent API. | ||
| use core::{ | ||
| marker::Unpin, | ||
| mem, | ||
| pin::Pin, | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| use crate::{ | ||
@@ -12,10 +20,2 @@ boxed::BitBox, | ||
| use core::{ | ||
| marker::Unpin, | ||
| mem, | ||
| pin::Pin, | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| impl<O, T> BitBox<O, T> | ||
@@ -22,0 +22,0 @@ where |
+7
-7
| //! Port of the `Box<[T]>` operator implementations. | ||
| use crate::{ | ||
| boxed::BitBox, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| }; | ||
| use core::{ | ||
@@ -27,2 +20,9 @@ mem::ManuallyDrop, | ||
| use crate::{ | ||
| boxed::BitBox, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| }; | ||
| impl<O, T, Rhs> BitAnd<Rhs> for BitBox<O, T> | ||
@@ -29,0 +29,0 @@ where |
| //! Unit tests for the `boxed` module. | ||
| use crate::prelude::*; | ||
| use core::convert::TryInto; | ||
| #[cfg(not(feature = "std"))] | ||
@@ -12,3 +8,6 @@ use alloc::{ | ||
| }; | ||
| use core::convert::TryInto; | ||
| use crate::prelude::*; | ||
| #[test] | ||
@@ -15,0 +14,0 @@ #[allow(deprecated)] |
+10
-11
| //! Non-operator trait implementations. | ||
| use crate::{ | ||
| boxed::BitBox, | ||
| mutability::Mut, | ||
| order::BitOrder, | ||
| ptr::BitSpan, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| use alloc::boxed::Box; | ||
| use core::{ | ||
@@ -41,2 +30,12 @@ borrow::{ | ||
| use crate::{ | ||
| boxed::BitBox, | ||
| mutability::Mut, | ||
| order::BitOrder, | ||
| ptr::BitSpan, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| #[cfg(not(tarpaulin_include))] | ||
@@ -43,0 +42,0 @@ impl<O, T> Borrow<BitSlice<O, T>> for BitBox<O, T> |
+7
-6
| //! Internal support utilities. | ||
| use crate::{ | ||
| order::BitOrder, | ||
| store::BitStore, | ||
| }; | ||
| use core::{ | ||
@@ -17,2 +12,7 @@ any::TypeId, | ||
| use crate::{ | ||
| order::BitOrder, | ||
| store::BitStore, | ||
| }; | ||
| /** Normalizes any range into a basic `Range`. | ||
@@ -117,5 +117,6 @@ | ||
| mod tests { | ||
| use super::*; | ||
| use std::panic::catch_unwind; | ||
| use super::*; | ||
| #[test] | ||
@@ -122,0 +123,0 @@ fn check_range_asserts() { |
+15
-16
@@ -21,13 +21,2 @@ /*! Representations of the [`BitSlice`] region memory model. | ||
| use crate::{ | ||
| index::{ | ||
| BitIdx, | ||
| BitTail, | ||
| }, | ||
| mem::BitMemory, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| }; | ||
| use core::{ | ||
@@ -46,2 +35,3 @@ fmt::{ | ||
| use funty::IsNumber; | ||
| use tap::{ | ||
@@ -51,5 +41,14 @@ pipe::Pipe, | ||
| }; | ||
| use wyz::fmt::FmtForward; | ||
| use crate::{ | ||
| index::{ | ||
| BitIdx, | ||
| BitTail, | ||
| }, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| }; | ||
| macro_rules! bit_domain { | ||
@@ -237,3 +236,3 @@ ($t:ident $(=> $m:ident)? $(@ $a:ident)?) => { | ||
| let (e, t) = h.span(bitspan.len()); | ||
| let w = T::Mem::BITS; | ||
| let w = T::Mem::BITS as u8; | ||
@@ -265,3 +264,3 @@ match (h.value(), e, t.value()) { | ||
| slice, | ||
| (T::Mem::BITS - head.value()) as usize, | ||
| (T::Mem::BITS as u8 - head.value()) as usize, | ||
| ); | ||
@@ -297,3 +296,3 @@ let (body, tail) = bit_domain!(split $($m)? | ||
| slice, | ||
| (T::Mem::BITS - head.value()) as usize, | ||
| (T::Mem::BITS as u8 - head.value()) as usize, | ||
| ); | ||
@@ -546,3 +545,3 @@ let (head, body) = ( | ||
| let tail = bitspan.tail(); | ||
| let bits = T::Mem::BITS; | ||
| let bits = T::Mem::BITS as u8; | ||
| let base = bitspan.address().to_const() as *const _; | ||
@@ -549,0 +548,0 @@ match (head.value(), elts, tail.value()) { |
+41
-39
@@ -203,2 +203,10 @@ /*! Batched load/store access to bitfields. | ||
| use core::{ | ||
| mem, | ||
| ptr, | ||
| }; | ||
| use funty::IsNumber; | ||
| use tap::pipe::Pipe; | ||
| use crate::{ | ||
@@ -222,10 +230,2 @@ access::BitAccess, | ||
| }; | ||
| use core::{ | ||
| mem, | ||
| ptr, | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| #[cfg(feature = "alloc")] | ||
@@ -276,3 +276,3 @@ use crate::{ | ||
| [`BitSlice`]: crate::slice::BitSlice | ||
| [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| [`M::BITS`]: funty::IsNumber::BITS | ||
| [`load`]: Self::load | ||
@@ -321,3 +321,3 @@ [`load_be`]: Self::load_be | ||
| /// [`BitMemory`]: crate::mem::BitMemory | ||
| /// [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| /// [`M::BITS`]: funty::IsNumber::BITS | ||
| /// [`load_be`]: Self::load_be | ||
@@ -372,3 +372,3 @@ /// [`load_le`]: Self::load_le | ||
| /// [`BitMemory`]: crate::mem::BitMemory | ||
| /// [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| /// [`M::BITS`]: funty::IsNumber::BITS | ||
| /// [`self.len()`]: crate::slice::BitSlice::len | ||
@@ -464,3 +464,3 @@ /// [`store_be`]: Self::store_be | ||
| /// | ||
| /// [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| /// [`M::BITS`]: funty::IsNumber::BITS | ||
| /// [`self.len()`]: crate::slice::BitSlice::len | ||
@@ -537,3 +537,3 @@ fn load_le<M>(&self) -> M | ||
| /// // Msb0: ├─ ├──┤ | ||
| /// // Bit pos: 14 15 19 | ||
| /// // Bit pos: 14 16 19 | ||
| /// | ||
@@ -550,3 +550,3 @@ /// assert_eq!( | ||
| /// | ||
| /// [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| /// [`M::BITS`]: funty::IsNumber::BITS | ||
| /// [`self.len()`]: crate::slice::BitSlice::len | ||
@@ -627,3 +627,3 @@ fn load_be<M>(&self) -> M | ||
| /// // Msb0: ├─ ├──┤ | ||
| /// // Bit pos: 14 15 19 | ||
| /// // Bit pos: 14 16 19 | ||
| /// | ||
@@ -636,3 +636,3 @@ /// lsb0[14 ..= 19].store_le(0b111001u8); | ||
| /// | ||
| /// [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| /// [`M::BITS`]: funty::IsNumber::BITS | ||
| /// [`self.len()`]: crate::slice::BitSlice::len | ||
@@ -713,3 +713,3 @@ fn store_le<M>(&mut self, value: M) | ||
| /// // Msb0: ├─ ├──┤ | ||
| /// // Bit pos: 14 15 19 | ||
| /// // Bit pos: 14 16 19 | ||
| /// | ||
@@ -722,3 +722,3 @@ /// lsb0[14 ..= 19].store_be(0b011110u8); | ||
| /// | ||
| /// [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| /// [`M::BITS`]: funty::IsNumber::BITS | ||
| /// [`self.len()`]: crate::slice::BitSlice::len | ||
@@ -821,4 +821,5 @@ fn store_be<M>(&mut self, value: M) | ||
| let shamt = head.value(); | ||
| if M::BITS > T::Mem::BITS - shamt { | ||
| accum <<= T::Mem::BITS - shamt; | ||
| let rshamt = T::Mem::BITS as u8 - shamt; | ||
| if M::BITS as u8 > rshamt { | ||
| accum <<= rshamt; | ||
| } | ||
@@ -906,3 +907,3 @@ else { | ||
| let shamt = tail.value(); | ||
| if M::BITS > shamt { | ||
| if M::BITS as u8 > shamt { | ||
| accum <<= shamt; | ||
@@ -958,4 +959,5 @@ } | ||
| set::<T, M>(elem, value, Lsb0::mask(head, None), shamt); | ||
| if M::BITS > T::Mem::BITS - shamt { | ||
| value >>= T::Mem::BITS - shamt; | ||
| let lshamt = T::Mem::BITS as u8 - shamt; | ||
| if M::BITS as u8 > lshamt { | ||
| value >>= lshamt; | ||
| } | ||
@@ -1018,3 +1020,3 @@ else { | ||
| let shamt = tail.value(); | ||
| if M::BITS > shamt { | ||
| if M::BITS as u8 > shamt { | ||
| value >>= shamt; | ||
@@ -1103,3 +1105,3 @@ } | ||
| Msb0::mask(head, tail), | ||
| T::Mem::BITS - tail.value(), | ||
| T::Mem::BITS as u8 - tail.value(), | ||
| ), | ||
@@ -1113,3 +1115,3 @@ Domain::Region { head, body, tail } => { | ||
| Msb0::mask(None, tail), | ||
| T::Mem::BITS - tail.value(), | ||
| T::Mem::BITS as u8 - tail.value(), | ||
| ); | ||
@@ -1126,4 +1128,4 @@ } | ||
| if let Some((head, elem)) = head { | ||
| let shamt = T::Mem::BITS - head.value(); | ||
| if M::BITS > shamt { | ||
| let shamt = T::Mem::BITS as u8 - head.value(); | ||
| if M::BITS as u8 > shamt { | ||
| accum <<= shamt; | ||
@@ -1195,3 +1197,3 @@ } | ||
| Msb0::mask(head, tail), | ||
| T::Mem::BITS - tail.value(), | ||
| T::Mem::BITS as u8 - tail.value(), | ||
| ), | ||
@@ -1214,3 +1216,3 @@ Domain::Region { head, body, tail } => { | ||
| let shamt = tail.value(); | ||
| if M::BITS > shamt { | ||
| if M::BITS as u8 > shamt { | ||
| accum <<= shamt; | ||
@@ -1224,3 +1226,3 @@ } | ||
| Msb0::mask(None, tail), | ||
| T::Mem::BITS - shamt, | ||
| T::Mem::BITS as u8 - shamt, | ||
| ); | ||
@@ -1268,3 +1270,3 @@ } | ||
| Msb0::mask(head, tail), | ||
| T::Mem::BITS - tail.value(), | ||
| T::Mem::BITS as u8 - tail.value(), | ||
| ), | ||
@@ -1274,4 +1276,4 @@ DomainMut::Region { head, body, tail } => { | ||
| set::<T, M>(elem, value, Msb0::mask(head, None), 0); | ||
| let shamt = T::Mem::BITS - head.value(); | ||
| if M::BITS > shamt { | ||
| let shamt = T::Mem::BITS as u8 - head.value(); | ||
| if M::BITS as u8 > shamt { | ||
| value >>= shamt; | ||
@@ -1296,3 +1298,3 @@ } | ||
| Msb0::mask(None, tail), | ||
| T::Mem::BITS - tail.value(), | ||
| T::Mem::BITS as u8 - tail.value(), | ||
| ); | ||
@@ -1338,3 +1340,3 @@ } | ||
| Msb0::mask(head, tail), | ||
| T::Mem::BITS - tail.value(), | ||
| T::Mem::BITS as u8 - tail.value(), | ||
| ), | ||
@@ -1347,5 +1349,5 @@ DomainMut::Region { head, body, tail } => { | ||
| Msb0::mask(None, tail), | ||
| T::Mem::BITS - tail.value(), | ||
| T::Mem::BITS as u8 - tail.value(), | ||
| ); | ||
| if M::BITS > tail.value() { | ||
| if M::BITS as u8 > tail.value() { | ||
| value >>= tail.value(); | ||
@@ -1462,3 +1464,3 @@ } | ||
| /// | ||
| /// [`M::BITS`]: crate::mem::BitMemory::BITS | ||
| /// [`M::BITS`]: funty::IsNumber::BITS | ||
| fn check<M>(action: &'static str, len: usize) | ||
@@ -1465,0 +1467,0 @@ where M: BitMemory { |
+7
-8
@@ -27,2 +27,9 @@ /*! I/O trait implementations. | ||
| use core::mem; | ||
| use std::io::{ | ||
| self, | ||
| Read, | ||
| Write, | ||
| }; | ||
| use crate::{ | ||
@@ -36,10 +43,2 @@ field::BitField, | ||
| use core::mem; | ||
| use std::io::{ | ||
| self, | ||
| Read, | ||
| Write, | ||
| }; | ||
| /** Mirrors the implementation on `[u8]` (found [here]). | ||
@@ -46,0 +45,0 @@ |
@@ -8,3 +8,2 @@ /*! Permutation testing. | ||
| use super::*; | ||
| #[cfg(not(miri))] | ||
@@ -11,0 +10,0 @@ use crate::prelude::*; |
+20
-19
@@ -42,7 +42,2 @@ /*! Well-typed counters and register descriptors. | ||
| use crate::{ | ||
| mem::BitRegister, | ||
| order::BitOrder, | ||
| }; | ||
| use core::{ | ||
@@ -70,2 +65,7 @@ any, | ||
| use crate::{ | ||
| mem::BitRegister, | ||
| order::BitOrder, | ||
| }; | ||
| /** A semantic index counter within a register element `R`. | ||
@@ -102,3 +102,3 @@ | ||
| [`BitOrder::at`]: crate::order::BitOrder::at | ||
| [`R::BITS`]: crate::mem::BitMemory::BITS | ||
| [`R::BITS`]: funty::IsNumber::BITS | ||
| [`bitvec`]: crate | ||
@@ -147,3 +147,3 @@ **/ | ||
| pub fn new(value: u8) -> Result<Self, BitIdxError<R>> { | ||
| if value >= R::BITS { | ||
| if value >= R::BITS as u8 { | ||
| return Err(BitIdxError::new(value)); | ||
@@ -175,3 +175,3 @@ } | ||
| debug_assert!( | ||
| value < R::BITS, | ||
| value < R::BITS as u8, | ||
| "Bit index {} cannot exceed type width {}", | ||
@@ -217,3 +217,3 @@ value, | ||
| unsafe { Self::new_unchecked(next & R::MASK) }, | ||
| next == R::BITS, | ||
| next == R::BITS as u8, | ||
| ) | ||
@@ -489,3 +489,3 @@ } | ||
| debug_assert!( | ||
| value >= R::BITS, | ||
| value >= R::BITS as u8, | ||
| "Bit index {} is valid for type width {}", | ||
@@ -587,3 +587,3 @@ value, | ||
| pub const LAST: Self = Self { | ||
| end: R::BITS, | ||
| end: R::BITS as u8, | ||
| _ty: PhantomData, | ||
@@ -612,3 +612,3 @@ }; | ||
| pub fn new(value: u8) -> Option<Self> { | ||
| if value > R::BITS { | ||
| if value > R::BITS as u8 { | ||
| return None; | ||
@@ -640,3 +640,3 @@ } | ||
| debug_assert!( | ||
| value <= R::BITS, | ||
| value <= R::BITS as u8, | ||
| "Bit tail {} cannot exceed type width {}", | ||
@@ -722,3 +722,3 @@ value, | ||
| let head = val & R::MASK; | ||
| let bits_in_head = (R::BITS - head) as usize; | ||
| let bits_in_head = (R::BITS as u8 - head) as usize; | ||
@@ -824,3 +824,3 @@ if len <= bits_in_head { | ||
| pub fn new(value: u8) -> Option<Self> { | ||
| if value >= R::BITS { | ||
| if value >= R::BITS as u8 { | ||
| return None; | ||
@@ -850,3 +850,3 @@ } | ||
| debug_assert!( | ||
| value < R::BITS, | ||
| value < R::BITS as u8, | ||
| "Bit position {} cannot exceed type width {}", | ||
@@ -1248,5 +1248,6 @@ value, | ||
| mod tests { | ||
| use tap::conv::TryConv; | ||
| use super::*; | ||
| use crate::order::Lsb0; | ||
| use tap::conv::TryConv; | ||
@@ -1511,7 +1512,7 @@ #[test] | ||
| fn render() { | ||
| use crate::order::Msb0; | ||
| #[cfg(not(feature = "std"))] | ||
| use alloc::format; | ||
| use crate::order::Msb0; | ||
| assert_eq!(format!("{:?}", BitIdx::<u8>::LAST), "BitIdx<u8>(111)"); | ||
@@ -1518,0 +1519,0 @@ assert_eq!(format!("{:?}", BitIdx::<u16>::LAST), "BitIdx<u16>(1111)"); |
+2
-2
@@ -24,3 +24,3 @@ /*! # `bitvec` — Addressable Bits | ||
| let literal_bits = bits![Lsb0, u16; 1, 0, 1, 1]; | ||
| assert_eq!(literal_bits.as_slice()[0], 0b1101); | ||
| assert_eq!(literal_bits.as_raw_slice()[0], 0b1101); | ||
@@ -117,3 +117,3 @@ let array_bool = bitarr![1; 40]; | ||
| pub type MySlice = BitSlice<Msb0, u8>; | ||
| pub type MyArray20 = bitarr![for 20, in Msb0, u8]; | ||
| pub type MyArray20 = BitArr!(for 20, in Msb0, u8); | ||
| # #[cfg(feature = "alloc")] | ||
@@ -120,0 +120,0 @@ pub type MyVec = BitVec<Msb0, u8>; |
+294
-240
@@ -9,2 +9,51 @@ //! Constructor macros for the crate’s collection types. | ||
| /** Constructs a type definition for a [`BitArray`]. | ||
| This macro takes a minimum number of bits, and optionally a set of [`BitOrder`] | ||
| and [`BitStore`] implementors, and creates a `BitArray` type definition that | ||
| satisfies them. Because this macro is used in type position, it uses | ||
| `PascalCase` rather than `snake_case` for its name. | ||
| # Grammar | ||
| ```rust | ||
| use bitvec::prelude::*; | ||
| use core::cell::Cell; | ||
| const CENT: usize = bitvec::mem::elts::<usize>(100); | ||
| let a: BitArr!(for 100) | ||
| = BitArray::<Lsb0, [usize; CENT]>::zeroed(); | ||
| let b: BitArr!(for 100, in u32) | ||
| = BitArray::<Lsb0, [u32; 4]>::zeroed(); | ||
| let c: BitArr!(for 100, in Msb0, Cell<u16>) | ||
| = BitArray::<Msb0, [Cell<u16>; 7]>::zeroed(); | ||
| ``` | ||
| The length expression must be a `const`-expression. It may be a literal or a | ||
| named `const` expression. The type arguments have no restrictions, so long as | ||
| they resolve to valid trait implementors. | ||
| [`BitArray`]: crate::array::BitArray | ||
| [`BitOrder`]: crate::order::BitOrder | ||
| [`BitStore`]: crate::store::BitStore | ||
| **/ | ||
| #[macro_export] | ||
| macro_rules! BitArr { | ||
| (for $len:expr, in $order:ty, $store:ty $(,)?) => { | ||
| $crate::array::BitArray::< | ||
| $order, [$store; $crate::mem::elts::<$store>($len)] | ||
| > | ||
| }; | ||
| (for $len:expr, in $store:ty $(,)?) => { | ||
| $crate::BitArr!(for $len, in $crate::order::Lsb0, $store) | ||
| }; | ||
| (for $len:expr) => { | ||
| $crate::BitArr!(for $len, in usize) | ||
| }; | ||
| } | ||
| /** Constructs a new [`BitArray`] from a bit-pattern description. | ||
@@ -34,12 +83,13 @@ | ||
| # Type Name Construction | ||
| ## `const` Production | ||
| In addition to the value construction, this macro can also construct the name of | ||
| a [`BitArray`] type that contains a requested number of bits. This is useful | ||
| for typing a binding before constructing a value for it. | ||
| Prepending the argument list with `const` (so `bitarr!(ARGS…)` becomes | ||
| `bitarr!(const ARGS…)`) causes the macro to only expand to code that can be used | ||
| in `const` contexts. This limits any supplied ordering to be **only** the tokens | ||
| `Lsb0`, `Msb0`, and `LocalBits`; no other token is permitted, even if the token | ||
| resolves to the same ordering implementation. | ||
| The argument syntax for this is a `for $BITS`, optionally followed by `, $TYPE` | ||
| or `, $ORDER, $TYPE`. `$BITS` may be any constant-evaluable `usize` expression. | ||
| `$ORDER` and `TYPE` may be any valid names or paths for the appropriate trait | ||
| implementations. | ||
| The macro expands into code that can be used to initialize a `const` or `static` | ||
| binding. This is the **only** way to construct a `BitArray` in `const` contexts, | ||
| until the `const` system permits generics and trait methods. | ||
@@ -64,5 +114,7 @@ # Examples | ||
| let c = bitarr![Lsb0, Cell<u16>; 0, 1, 0, 0, 1]; | ||
| let d = bitarr![Msb0, AtomicU32; 0, 0, 1, 0, 1]; | ||
| radium::if_atomic! { if atomic(32) { | ||
| let d = bitarr![Msb0, AtomicU32; 0, 0, 1, 0, 1]; | ||
| } } | ||
| let e: bitarr!(for 20, in LocalBits, u8) = bitarr![LocalBits, u8; 0; 20]; | ||
| let e: BitArr!(for 20, in LocalBits, u8) = bitarr![LocalBits, u8; 0; 20]; | ||
| ``` | ||
@@ -77,21 +129,76 @@ | ||
| macro_rules! bitarr { | ||
| // Type constructors | ||
| /* `const`-expression constructors. | ||
| (for $len:expr, in $order:ty, $store:ident) => { | ||
| $crate::array::BitArray::< | ||
| $order, | ||
| [$store; $crate::mem::elts::<$store>($len)], | ||
| > | ||
| }; | ||
| These arms expand to expressions which are valid to use in `const` position, | ||
| such as within `const fn` bodies, or as the initializers of `static` or | ||
| `const` bindings. | ||
| (for $len:expr, in $store:ident) => { | ||
| $crate::bitarr!(for $len, in $crate::order::Lsb0, $store) | ||
| }; | ||
| They are more restricted than the general variants below, because the trait | ||
| system is not usable in `const` contexts and thus these expansions can only | ||
| use codepaths defined within this module, and not any of the general crate | ||
| systems. | ||
| (for $len:expr) => { | ||
| $crate::bitarr!(for $len, in usize) | ||
| }; | ||
| All valid invocations with a leading `const` token will remain valid if the | ||
| `const` is removed, though their expansion may cease to be valid in `const` | ||
| contexts. | ||
| */ | ||
| (const $order:ty, $store:ty; $val:expr; $len:expr) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Mem = <$store as $crate::store::BitStore>::Mem; | ||
| // Value constructors | ||
| const ELTS: usize = $crate::mem::elts::<$store>($len); | ||
| const ELEM: Mem = $crate::__extend_bool!($val, $store); | ||
| const DATA: [Mem; ELTS] = [ELEM; ELTS]; | ||
| type This = $crate::array::BitArray<$order, [$store; ELTS]>; | ||
| unsafe { core::mem::transmute::<_, This>(DATA) } | ||
| }}; | ||
| (const $val:expr; $len:expr) => {{ | ||
| $crate::bitarr!(const $crate::order::Lsb0, usize; $val; $len) | ||
| }}; | ||
| (const $order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Celled = core::cell::Cell<$store>; | ||
| const ELTS: usize = $crate::__count_elts!($store; $($val),*); | ||
| type Data = [Celled; ELTS]; | ||
| const DATA: Data = | ||
| $crate::__encode_bits!($order, Cell<$store>; $($val),*); | ||
| type This = $crate::array::BitArray<$order, Data>; | ||
| unsafe { core::mem::transmute::<_, This>(DATA) } | ||
| }}; | ||
| (const $order:ident, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| use $crate::macros::internal::core; | ||
| const ELTS: usize = $crate::__count_elts!($store; $($val),*); | ||
| type Data = [$store; ELTS]; | ||
| const DATA: Data = $crate::__encode_bits!($order, $store; $($val),*); | ||
| type This = $crate::array::BitArray<$order, Data>; | ||
| unsafe { core::mem::transmute::<_, This>(DATA) } | ||
| }}; | ||
| (const $($val:expr),* $(,)?) => {{ | ||
| $crate::bitarr!(const Lsb0, usize; $($val),*) | ||
| }}; | ||
| /* Non-`const` constructors. | ||
| These expansions are allowed to produce that does not run in `const` | ||
| contexts. While it is *likely* that the expansions will be evaluated at | ||
| compile-time, this is done in LLVM, not in Rust MIR. | ||
| */ | ||
| // Bit-repetition syntax. | ||
| ($order:ty, $store:ty; $val:expr; $len:expr) => {{ | ||
| $crate::bitarr!(const $order, $store; $val; $len) | ||
| }}; | ||
| ($val:expr; $len:expr) => {{ | ||
| $crate::bitarr!(const $val; $len) | ||
| }}; | ||
| // Bit-sequence syntax. | ||
| /* The duplicate matchers differing in `:ident` and `:path` exploit a rule | ||
@@ -109,132 +216,38 @@ of macro expansion so that the literal tokens `Lsb0`, `Msb0`, and | ||
| ($order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => { | ||
| $crate::array::BitArray::< | ||
| $order, [ | ||
| $crate::macros::internal::core::cell::Cell<$store>; | ||
| $crate::__count_elts!($store; $($val),*) | ||
| ], | ||
| >::new( | ||
| $crate::__encode_bits!($order, Cell<$store>; $($val),*) | ||
| ) | ||
| }; | ||
| ($order:ident, $store:ident; $($val:expr),* $(,)?) => { | ||
| $crate::array::BitArray::< | ||
| $order, | ||
| [$store; $crate::__count_elts!($store; $($val),*)], | ||
| >::new( | ||
| $crate::__encode_bits!($order, $store; $($val),*) | ||
| ) | ||
| }; | ||
| ($order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Celled = core::cell::Cell<$store>; | ||
| ($order:path, Cell<$store:ident>; $($val:expr),* $(,)?) => { | ||
| $crate::array::BitArray::< | ||
| $order, [ | ||
| $crate::macros::internal::core::cell::Cell<$store>; | ||
| $crate::__count_elts!($store; $($val),*) | ||
| ], | ||
| >::new( | ||
| $crate::__encode_bits!($order, Cell<$store>; $($val),*) | ||
| ) | ||
| }; | ||
| ($order:path, $store:ident; $($val:expr),* $(,)?) => { | ||
| $crate::array::BitArray::< | ||
| $order, | ||
| [$store; $crate::__count_elts!($store; $($val),*)], | ||
| >::new( | ||
| $crate::__encode_bits!($order, $store; $($val),*) | ||
| ) | ||
| }; | ||
| const ELTS: usize = $crate::__count_elts!($store; $($val),*); | ||
| type Data = [Celled; ELTS]; | ||
| type This = $crate::array::BitArray<$order, Data>; | ||
| ($order:ident; $($val:expr),* $(,)?) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bitarr!($order, usize; $($val),*) | ||
| This::new($crate::__encode_bits!($order, Cell<$store>; $($val),*)) | ||
| }}; | ||
| ($order:ident, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| const ELTS: usize = $crate::__count_elts!($store; $($val),*); | ||
| type This = $crate::array::BitArray<$order, [$store; ELTS]>; | ||
| ($order:path; $($val:expr),* $(,)?) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bitarr!($order, usize; $($val),*) | ||
| This::new($crate::__encode_bits!($order, $store; $($val),*)) | ||
| }}; | ||
| ($order:ident, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| let elem = $crate::__extend_bool!($val, $store); | ||
| let base = [elem; $crate::mem::elts::<$store>($len)]; | ||
| let elts = unsafe { | ||
| $crate::macros::internal::core::mem::transmute(base) | ||
| }; | ||
| $crate::array::BitArray::< | ||
| $order, | ||
| [Cell<$store>; $crate::mem::elts::<$store>($len)], | ||
| >::new(elts) | ||
| }}; | ||
| ($order:ident, $store:ident; $val:expr; $len:expr) => {{ | ||
| use $crate::macros::internal::core::mem::MaybeUninit; | ||
| use $crate::store::BitStore as _; | ||
| const LEN: usize = $crate::mem::elts::<$store>($len); | ||
| ($order:path, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Celled = core::cell::Cell<$store>; | ||
| // Create a local copy of the base element. | ||
| let elem = $crate::__extend_bool!($val, $store); | ||
| // Create the array. | ||
| let mut elts: MaybeUninit<[$store; LEN]> = MaybeUninit::uninit(); | ||
| // Get the address of the base element in the array | ||
| let mut addr = elts.as_mut_ptr() as *mut $store; | ||
| for _ in 0 .. LEN { | ||
| unsafe { | ||
| // Copy `elem` into each element of the array. | ||
| addr.write(<$store>::from(elem.load_value())); | ||
| addr = addr.add(1); | ||
| } | ||
| } | ||
| $crate::array::BitArray::<$order, [$store; LEN]>::new(unsafe { | ||
| elts.assume_init() | ||
| }) | ||
| // Constructing an array of non-`Copy` objects is really hard. | ||
| }}; | ||
| const ELTS: usize = $crate::__count_elts!($store; $($val),*); | ||
| type This = $crate::array::BitArray<$order, [Celled; ELTS]>; | ||
| ($order:path, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| let elem = $crate::__extend_bool!($val, $store); | ||
| let base = [elem; $crate::mem::elts::<$store>($len)]; | ||
| let elts = unsafe { | ||
| $crate::macros::internal::core::mem::transmute(base) | ||
| }; | ||
| $crate::array::BitArray::< | ||
| $order, | ||
| [Cell<$store>; $crate::mem::elts::<$store>($len)], | ||
| >::new(elts) | ||
| This::new($crate::__encode_bits!($order, Cell<$store>; $($val),*)) | ||
| }}; | ||
| ($order:path, $store:ident; $val:expr; $len:expr) => {{ | ||
| use $crate::macros::internal::core::mem::MaybeUninit; | ||
| use $crate::store::BitStore as _; | ||
| const LEN: usize = $crate::mem::elts::<$store>($len); | ||
| ($order:path, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| const ELTS: usize = $crate::__count_elts!($store; $($val),*); | ||
| type This = $crate::array::BitArray<$order, [$store; ELTS]>; | ||
| let elem = $crate::__extend_bool!($val, $store); | ||
| let mut elts: MaybeUninit<[$store; LEN]> = MaybeUninit::uninit(); | ||
| let mut addr = elts.as_mut_ptr() as *mut $store; | ||
| for _ in 0 .. LEN { | ||
| unsafe { | ||
| addr.write(<$store>::from(elem.load_value())); | ||
| addr = addr.add(1); | ||
| } | ||
| } | ||
| $crate::array::BitArray::<$order, [$store; LEN]>::new(unsafe { | ||
| elts.assume_init() | ||
| }) | ||
| This::new($crate::__encode_bits!($order, $store; $($val),*)) | ||
| }}; | ||
| ($order:ident; $val:expr; $len:expr) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bitarr!($order, usize; $val; $len) | ||
| }}; | ||
| ($order:path; $val:expr; $len:expr) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bitarr!($order, usize; $val; $len) | ||
| }}; | ||
| ($($val:expr),* $(,)?) => { | ||
| $crate::bitarr!(Lsb0, usize; $($val),*) | ||
| }; | ||
| ($val:expr; $len:expr) => { | ||
| $crate::bitarr!(Lsb0, usize; $val; $len) | ||
| }; | ||
| } | ||
@@ -272,2 +285,17 @@ | ||
| ## `static` Production | ||
| Prepending the argument list with `static` or `static mut` (so `bits!(ARGS…)` | ||
| becomes `bits!(static [mut] ARGS…)`) causes the macro to expand to code that | ||
| emits a hidden `static` or `static mut` value, initialized with a | ||
| `bitarr!(const ARGS…)` expansion and then reborrowed. The name of the hidden | ||
| static object does not escape the macro invocation, and so the returned | ||
| `BitSlice` handle is the single point of access to it. | ||
| Because both indexing and mutable reborrows are forbidden in `const` contexts, | ||
| the produced `BitSlice` references can only be bound to `let`, not to `static`. | ||
| They have the `&'static` lifetime, but to give the *names* a `static` binding, | ||
| you must use `bitarr!(const ARGS…)` and then borrowed as a `BitSlice` at the | ||
| point of use. | ||
| # Examples | ||
@@ -304,31 +332,99 @@ | ||
| macro_rules! bits { | ||
| // Sequence syntax `[bit (, bit)*]` or `[(bit ,)*]`. | ||
| (static mut $order:ty, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Celled = core::cell::Cell<$store>; | ||
| static mut DATA: $crate::BitArr!(for $len, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $val; $len); | ||
| unsafe { | ||
| &mut *( | ||
| DATA.get_unchecked_mut(.. $len) | ||
| as *mut $crate::slice::BitSlice<$order, $store> | ||
| as *mut $crate::slice::BitSlice<$order, Celled> | ||
| ) | ||
| } | ||
| }}; | ||
| (static mut $order:ty, $store:ident; $val:expr; $len:expr) => {{ | ||
| static mut DATA: $crate::BitArr!(for $len, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $val; $len); | ||
| unsafe { DATA.get_unchecked_mut(.. $len) } | ||
| }}; | ||
| (static mut $val:expr; $len:expr) => {{ | ||
| static mut DATA: $crate::BitArr!(for $len) = | ||
| $crate::bitarr!(const $crate::order::Lsb0, usize; $val; $len); | ||
| unsafe { DATA.get_unchecked_mut(.. $len) } | ||
| }}; | ||
| // Explicit order and store. | ||
| (static mut $order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Celled = core::cell::Cell<$store>; | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| (mut $order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| &mut $crate::bitarr![$order, Cell<$store>; $($val),*][.. $crate::__count!($($val),*)] | ||
| static mut DATA: $crate::BitArr!(for BITS, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $($val),*); | ||
| unsafe { | ||
| &mut *( | ||
| DATA.get_unchecked_mut(.. BITS) | ||
| as *mut $crate::slice::BitSlice<$order, $store> | ||
| as *mut $crate::slice::BitSlice<$order, Celled> | ||
| ) | ||
| } | ||
| }}; | ||
| (mut $order:ident, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| &mut $crate::bitarr![$order, $store; $($val),*][.. $crate::__count!($($val),*)] | ||
| (static mut $order:ident, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| static mut DATA: $crate::BitArr!(for BITS, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $($val),*); | ||
| unsafe { DATA.get_unchecked_mut(.. BITS) } | ||
| }}; | ||
| (static mut $($val:expr),* $(,)?) => {{ | ||
| $crate::bits!(static mut Lsb0, usize; $($val),*) | ||
| }}; | ||
| (mut $order:path, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| &mut $crate::bitarr![$order, Cell<$store>; $($val),*][.. $crate::__count!($($val),*)] | ||
| (static $order:ty, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Celled = core::cell::Cell<$store>; | ||
| static DATA: $crate::BitArr!(for $len, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $val; $len); | ||
| unsafe { | ||
| &*( | ||
| DATA.get_unchecked(.. $len) | ||
| as *const $crate::slice::BitSlice<$order, $store> | ||
| as *const $crate::slice::BitSlice<$order, Celled> | ||
| ) | ||
| } | ||
| }}; | ||
| (mut $order:path, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| &mut $crate::bitarr![$order, $store; $($val),*][.. $crate::__count!($($val),*)] | ||
| (static $order:ty, $store:ident; $val:expr; $len:expr) => {{ | ||
| static DATA: $crate::BitArr!(for $len, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $val; $len); | ||
| unsafe { DATA.get_unchecked(.. $len) } | ||
| }}; | ||
| (static $val:expr; $len:expr) => {{ | ||
| static DATA: $crate::BitArr!(for $len) = | ||
| $crate::bitarr!(const $crate::order::Lsb0, usize; $val; $len); | ||
| unsafe { DATA.get_unchecked(.. $len) } | ||
| }}; | ||
| // Explicit order, default store. | ||
| (static $order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| use $crate::macros::internal::core; | ||
| type Celled = core::cell::Cell<$store>; | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| (mut $order:ident; $($val:expr),* $(,)?) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!(mut $order, usize; $($val),*) | ||
| static mut DATA: $crate::BitArr!(for BITS, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $($val),*); | ||
| unsafe { | ||
| &*( | ||
| DATA.get_unchecked_mut(.. BITS) | ||
| as *const $crate::slice::BitSlice<$order, $store> | ||
| as *const $crate::slice::BitSlice<$order, Celled> | ||
| ) | ||
| } | ||
| }}; | ||
| (mut $order:path; $($val:expr),* $(,)?) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!(mut $order, usize; $($val),*) | ||
| (static $order:ident, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| static DATA: $crate::BitArr!(for BITS, in $order, $store) = | ||
| $crate::bitarr!(const $order, $store; $($val),*); | ||
| unsafe { DATA.get_unchecked(.. BITS) } | ||
| }}; | ||
| (static $($val:expr),* $(,)?) => {{ | ||
| $crate::bits!(static Lsb0, usize; $($val),*) | ||
| }}; | ||
@@ -339,31 +435,33 @@ // Repetition syntax `[bit ; count]`. | ||
| // Explicit order and store. | ||
| (mut $order:ident, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| &mut $crate::bitarr![$order, Cell<$store>; $val; $len][.. $len] | ||
| (mut $order:ty, $store:ty; $val:expr; $len:expr) => {{ | ||
| &mut $crate::bitarr!($order, $store; $val; $len)[.. $len] | ||
| }}; | ||
| (mut $order:ident, $store:ident; $val:expr; $len:expr) => {{ | ||
| &mut $crate::bitarr![$order, $store; $val; $len][.. $len] | ||
| }}; | ||
| // Default order and store. | ||
| (mut $val:expr; $len:expr) => { | ||
| $crate::bits!(mut $crate::order::Lsb0, usize; $val; $len) | ||
| }; | ||
| (mut $order:path, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| &mut $crate::bitarr![$order, Cell<$store>; $val; $len][.. $len] | ||
| }}; | ||
| (mut $order:path, $store:ident; $val:expr; $len:expr) => {{ | ||
| &mut $crate::bitarr![$order, $store; $val; $len][.. $len] | ||
| }}; | ||
| // Sequence syntax `[bit (, bit)*]` or `[(bit ,)*]`. | ||
| // Explicit order, default store. | ||
| // Explicit order and store. | ||
| (mut $order:ident; $val:expr; $len:expr) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!(mut $order, usize; $val; $len) | ||
| (mut $order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &mut $crate::bitarr!($order, Cell<$store>; $($val),*)[.. BITS] | ||
| }}; | ||
| (mut $order:ident, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &mut $crate::bitarr!($order, $store; $($val),*)[.. BITS] | ||
| }}; | ||
| (mut $order:path; $val:expr; $len:expr) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!(mut $order, usize; $val; $len) | ||
| (mut $order:path, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &mut $crate::bitarr!($order, Cell<$store>; $($val),*)[.. BITS] | ||
| }}; | ||
| (mut $order:path, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &mut $crate::bitarr!($order, $store; $($val),*)[.. BITS] | ||
| }}; | ||
| // Default order and store. | ||
| (mut $($val:expr),* $(,)?) => { | ||
@@ -373,66 +471,33 @@ $crate::bits!(mut Lsb0, usize; $($val),*) | ||
| (mut $val:expr; $len:expr) => { | ||
| $crate::bits!(mut Lsb0, usize; $val; $len) | ||
| // Repeat everything from above, but now immutable. | ||
| ($order:ty, $store:ty; $val:expr; $len:expr) => {{ | ||
| &$crate::bitarr!($order, $store; $val; $len)[.. $len] | ||
| }}; | ||
| ($val:expr; $len:expr) => { | ||
| $crate::bits!($crate::order::Lsb0, usize; $val; $len) | ||
| }; | ||
| // Repeat everything from above, but now immutable. | ||
| ($order:ident, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| &$crate::bitarr![$order, Cell<$store>; $($val),*][.. $crate::__count!($($val),*)] | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &$crate::bitarr!($order, Cell<$store>; $($val),*)[.. BITS] | ||
| }}; | ||
| ($order:ident, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| &$crate::bitarr![$order, $store; $($val),*][.. $crate::__count!($($val),*)] | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &$crate::bitarr!($order, $store; $($val),*)[.. BITS] | ||
| }}; | ||
| ($order:path, Cell<$store:ident>; $($val:expr),* $(,)?) => {{ | ||
| &$crate::bitarr![$order, Cell<$store>; $($val),*][.. $crate::__count!($($val),*)] | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &$crate::bitarr!($order, Cell<$store>; $($val),*)[.. BITS] | ||
| }}; | ||
| ($order:path, $store:ident; $($val:expr),* $(,)?) => {{ | ||
| &$crate::bitarr![$order, $store; $($val),*][.. $crate::__count!($($val),*)] | ||
| const BITS: usize = $crate::__count!($($val),*); | ||
| &$crate::bitarr!($order, $store; $($val),*)[.. BITS] | ||
| }}; | ||
| ($order:ident; $($val:expr),* $(,)?) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!($order, usize; $($val),*) | ||
| }}; | ||
| ($order:path; $($val:expr),* $(,)?) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!($order, usize; $($val),*) | ||
| }}; | ||
| ($order:ident, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| &$crate::bitarr![$order, Cell<$store>; $val; $len][.. $len] | ||
| }}; | ||
| ($order:ident, $store:ident; $val:expr; $len:expr) => {{ | ||
| &$crate::bitarr![$order, $store; $val; $len][.. $len] | ||
| }}; | ||
| ($order:path, Cell<$store:ident>; $val:expr; $len:expr) => {{ | ||
| &$crate::bitarr![$order, Cell<$store>; $val; $len][.. $len] | ||
| }}; | ||
| ($order:path, $store:ident; $val:expr; $len:expr) => {{ | ||
| &$crate::bitarr![$order, $store; $val; $len][.. $len] | ||
| }}; | ||
| ($order:ident; $val:expr; $len:expr) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!($order, usize; $val; $len) | ||
| }}; | ||
| ($order:path; $val:expr; $len:expr) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::bits!($order, usize; $val; $len) | ||
| }}; | ||
| // Default order and store. | ||
| // These must be last to prevent spurious matches on the type arguments. | ||
| ($($val:expr),* $(,)?) => { | ||
| $crate::bits!(Lsb0, usize; $($val),*) | ||
| }; | ||
| ($val:expr; $len:expr) => { | ||
| $crate::bits!(Lsb0, usize; $val; $len) | ||
| }; | ||
| } | ||
@@ -495,19 +560,8 @@ | ||
| // values for the repetition count. | ||
| ($order:ty, Cell<$store:ident>; $val:expr; $rep:expr) => { | ||
| $crate::vec::BitVec::< | ||
| $order, | ||
| $crate::macros::internal::core::cell::Cell<$store> | ||
| >::repeat($val != 0, $rep) | ||
| ($order:ty, $store:ty; $val:expr; $len:expr) => { | ||
| $crate::vec::BitVec::<$order, $store>::repeat($val != 0, $len) | ||
| }; | ||
| ($order:ty, $store:ident; $val:expr; $rep:expr) => { | ||
| $crate::vec::BitVec::<$order, $store>::repeat($val != 0, $rep) | ||
| }; | ||
| ($order:ty; $val:expr; $rep:expr) => {{ | ||
| $crate::macros::internal::__deprecated_order_no_store(); | ||
| $crate::vec::BitVec::<$order, usize>::repeat($val != 0, $rep) | ||
| }}; | ||
| ($val:expr; $rep:expr) => { | ||
| $crate::vec::BitVec::<$crate::order::Lsb0, usize>::repeat($val != 0, $rep) | ||
| ($val:expr; $len:expr) => { | ||
| $crate::bitvec!($crate::order::Lsb0, usize; $val; $len) | ||
| }; | ||
@@ -514,0 +568,0 @@ |
+62
-48
@@ -115,25 +115,24 @@ /*! Internal implementation macros for the public exports. | ||
| /* These two blocks are the last invoked. They require a sequence of chunked | ||
| element candidates (the `$elem` token is actually an opaque cluster of bit | ||
| /* This block is the last invoked. It requires a sequence of chunked element | ||
| candidates (the `$bit` tokens are actually an opaque sequence of bit | ||
| expressions), followed by literal `0` tokens. Tokens provided by the caller | ||
| are already opaque; only the zeros created in the previous arm are visible. | ||
| As such, these enter only when the caller-provided bit tokens are exhausted. | ||
| As such, this enters only when the caller-provided bit tokens are exhausted. | ||
| Once entered, these matchers convert each tuple of bit expressions into the | ||
| requested storage type, and collect them into an array. This array is the | ||
| Once entered, this matcher converts each tuple of bit expressions into the | ||
| requested storage type, and collects them into an array. This array is the | ||
| return value of the originally-called macro. | ||
| */ | ||
| ($ord:tt, $typ:ty as $uint:ident as usize, [$( ( $($elem:tt),* ) )*]; $(0,)*) => { | ||
| // `usize` must be constructed as a fixed-width integer, converted into | ||
| // `usize`, and *then* converted into the final storage type. | ||
| [$(<$typ as From<usize>>::from( | ||
| $crate::__make_elem!($ord, $uint as $uint; $($elem),*) as usize | ||
| ( | ||
| $ord:tt, | ||
| $typ:ty as $uint:ident $(as usize)?, | ||
| [$( ( $($bit:tt),* ) )*]; $(0,)* | ||
| ) => { | ||
| [$($crate::__make_elem!( | ||
| $ord, | ||
| $typ as $uint; | ||
| $($bit),* | ||
| )),*] | ||
| }; | ||
| ($ord:tt, $typ:ty as $uint:ident, [$( ( $($elem:tt),* ) )*]; $(0,)*) => { | ||
| [$( | ||
| $crate::__make_elem!($ord, $typ as $uint; $($elem),*) | ||
| ),*] | ||
| }; | ||
@@ -263,2 +262,8 @@ /* These matchers chunk a stream of bit expressions into storage elements. | ||
| to the provided ordering. | ||
| # Safety | ||
| This uses `mem::transmute` internally, and so must be invoked within a | ||
| caller-provided `unsafe` block. It does not use its own `unsafe` block in order | ||
| to avoid a compiler warning about nested blocks. | ||
| **/ | ||
@@ -272,4 +277,5 @@ #[doc(hidden)] | ||
| $e:expr, $f:expr, $g:expr, $h:expr | ||
| ),*) => { | ||
| <$typ as From<$uint>>::from($crate::__ty_from_bytes!( | ||
| ),*) => { unsafe { | ||
| use $crate::macros::internal::core; | ||
| const ELEM: $uint = $crate::__ty_from_bytes!( | ||
| Lsb0, $uint, [$($crate::macros::internal::u8_from_le_bits( | ||
@@ -279,9 +285,11 @@ $a != 0, $b != 0, $c != 0, $d != 0, | ||
| )),*] | ||
| )) | ||
| }; | ||
| ); | ||
| core::mem::transmute::<$uint, $typ>(ELEM) | ||
| } }; | ||
| (Msb0, $typ:ty as $uint:ident; $( | ||
| $a:expr, $b:expr, $c:expr, $d:expr, | ||
| $e:expr, $f:expr, $g:expr, $h:expr | ||
| ),*) => { | ||
| <$typ as From<$uint>>::from($crate::__ty_from_bytes!( | ||
| ),*) => { unsafe { | ||
| use $crate::macros::internal::core; | ||
| const ELEM: $uint = $crate::__ty_from_bytes!( | ||
| Msb0, $uint, [$($crate::macros::internal::u8_from_be_bits( | ||
@@ -291,9 +299,11 @@ $a != 0, $b != 0, $c != 0, $d != 0, | ||
| )),*] | ||
| )) | ||
| }; | ||
| ); | ||
| core::mem::transmute::<$uint, $typ>(ELEM) | ||
| } }; | ||
| (LocalBits, $typ:ty as $uint:ident; $( | ||
| $a:expr, $b:expr, $c:expr, $d:expr, | ||
| $e:expr, $f:expr, $g:expr, $h:expr | ||
| ),*) => { | ||
| <$typ as From<$uint>>::from($crate::__ty_from_bytes!( | ||
| ),*) => { unsafe { | ||
| use $crate::macros::internal::core; | ||
| const ELEM: $uint = $crate::__ty_from_bytes!( | ||
| LocalBits, $uint, [$($crate::macros::internal::u8_from_ne_bits( | ||
@@ -303,6 +313,8 @@ $a != 0, $b != 0, $c != 0, $d != 0, | ||
| )),*] | ||
| )) | ||
| }; | ||
| ); | ||
| core::mem::transmute::<$uint, $typ>(ELEM) | ||
| } }; | ||
| // Otherwise, invoke `BitOrder` for each bit and accumulate. | ||
| ($ord:tt, $typ:ty as $uint:ident; $($bit:expr),* $(,)?) => {{ | ||
| ($ord:tt, $typ:ty as $uint:ident; $($bit:expr),* $(,)?) => { unsafe { | ||
| use $crate::macros::internal::core; | ||
| let mut tmp: $uint = 0; | ||
@@ -314,16 +326,27 @@ let _bits = $crate::slice::BitSlice::<$ord, $uint>::from_element_mut( | ||
| $( _bits.set(_idx, $bit != 0); _idx += 1; )* | ||
| <$typ as From<$uint>>::from(tmp) | ||
| }}; | ||
| core::mem::transmute::<$uint, $typ>(tmp) | ||
| } }; | ||
| } | ||
| /// Extend a single bit to fill an element. | ||
| /** Extend a single bit to fill an element. | ||
| # Parameters | ||
| - `$val`: An integer expression to be tested as non-zero. | ||
| - `$typ`: Some opaque type expression. | ||
| # Returns | ||
| `$val != 0`, as `<$typ as BitStore>::Mem`. | ||
| **/ | ||
| #[doc(hidden)] | ||
| #[macro_export] | ||
| macro_rules! __extend_bool { | ||
| ($val:expr, $typ:tt) => { | ||
| $typ::from([ | ||
| <<$typ as BitStore>::Mem as $crate::macros::internal::funty::IsInteger>::ZERO, | ||
| <<$typ as BitStore>::Mem as $crate::mem::BitRegister>::ALL, | ||
| ][($val != 0) as usize]) | ||
| }; | ||
| ($val:expr, $typ:tt) => {{ | ||
| type Mem = <$typ as BitStore>::Mem; | ||
| [ | ||
| <Mem as $crate::macros::internal::funty::IsInteger>::ZERO, | ||
| <Mem as $crate::mem::BitRegister>::ALL, | ||
| ][($val != 0) as usize] | ||
| }}; | ||
| } | ||
@@ -429,16 +452,7 @@ | ||
| #[doc(hidden)] | ||
| #[cfg(target_endian = "little")] | ||
| pub use self::u8_from_le_bits as u8_from_ne_bits; | ||
| #[doc(hidden)] | ||
| #[cfg(target_endian = "big")] | ||
| pub use self::u8_from_be_bits as u8_from_ne_bits; | ||
| #[doc(hidden)] | ||
| #[cfg(not(tarpaulin_include))] | ||
| #[deprecated = "Ordering-only macro constructors are deprecated. Specify a \ | ||
| storage type as well, or remove the ordering and use the \ | ||
| default."] | ||
| pub const fn __deprecated_order_no_store() { | ||
| } | ||
| #[cfg(target_endian = "little")] | ||
| pub use self::u8_from_le_bits as u8_from_ne_bits; | ||
@@ -445,0 +459,0 @@ #[cfg(test)] |
+67
-12
@@ -5,14 +5,23 @@ //! Unit tests for the `macros` module. | ||
| use core::cell::Cell; | ||
| use funty::IsNumber; | ||
| use crate::prelude::*; | ||
| use core::cell::Cell; | ||
| #[test] | ||
| fn compile_bitarr_typedef() { | ||
| #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] | ||
| struct Slots { | ||
| all: bitarr!(for 10, in Msb0, u8), | ||
| typ: bitarr!(for 10, in u8), | ||
| def: bitarr!(for 10), | ||
| all: BitArr!(for 10, in Msb0, u8), | ||
| typ: BitArr!(for 10, in u8), | ||
| def: BitArr!(for 10), | ||
| } | ||
| static SLOTS: Slots = Slots { | ||
| all: bitarr!(const Msb0, u8; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), | ||
| typ: bitarr!(const Lsb0, u8; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), | ||
| def: bitarr!(const 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), | ||
| }; | ||
| let slots = Slots { | ||
@@ -24,2 +33,4 @@ all: bitarr!(Msb0, u8; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), | ||
| assert_eq!(SLOTS, slots); | ||
| assert_eq!(slots.all.value(), [!0u8, 192]); | ||
@@ -32,2 +43,47 @@ assert_eq!(slots.typ.value(), [!0u8, 3]); | ||
| #[test] | ||
| fn constexpr_macros() { | ||
| const A: BitArr!(for 20, in Lsb0, Cell<u8>) = | ||
| bitarr!(const Lsb0, Cell<u8>; 1; 20); | ||
| let a = A; | ||
| assert_eq!(a.len(), 24); | ||
| assert!(a.all()); | ||
| const B: BitArr!(for 20) = bitarr!(const 1; 20); | ||
| let b = B; | ||
| assert_eq!(b.len(), <usize as IsNumber>::BITS as usize); | ||
| assert!(b.all()); | ||
| const C: BitArr!(for 5, in Msb0, Cell<u16>) = | ||
| bitarr!(const Msb0, Cell<u16>; 1, 0, 1, 1, 0); | ||
| let c = C; | ||
| assert_eq!(c[.. 5], bits![1, 0, 1, 1, 0]); | ||
| const D: BitArr!(for 5, in Lsb0, u32) = | ||
| bitarr!(const Lsb0, u32; 1, 0, 1, 1, 0); | ||
| let d = D; | ||
| assert_eq!(d[.. 5], bits![1, 0, 1, 1, 0]); | ||
| let _: &'static mut BitSlice<Msb0, Cell<u16>> = | ||
| bits!(static mut Msb0, Cell<u16>; 1; 20); | ||
| let _: &'static mut BitSlice<Lsb0, u32> = bits!(static mut Lsb0, u32; 1; 20); | ||
| let _: &'static mut BitSlice = bits!(static mut 1; 20); | ||
| let _: &'static mut BitSlice<Msb0, Cell<u16>> = | ||
| bits!(static mut Msb0, Cell<u16>; 1, 0, 1, 1, 0); | ||
| let _: &'static mut BitSlice<Lsb0, u32> = | ||
| bits!(static mut Lsb0, u32; 1, 0, 1, 1, 0); | ||
| let _: &'static mut BitSlice = bits!(static mut 1, 0, 1, 1, 0); | ||
| let _: &'static BitSlice<Msb0, Cell<u16>> = | ||
| bits!(static Msb0, Cell<u16>; 1; 20); | ||
| let _: &'static BitSlice<Lsb0, u32> = bits!(static Lsb0, u32; 1; 20); | ||
| let _: &'static BitSlice = bits!(static 1; 20); | ||
| let _: &'static BitSlice<Msb0, Cell<u16>> = | ||
| bits!(static Msb0, Cell<u16>; 1, 0, 1, 1, 0); | ||
| let _: &'static BitSlice<Lsb0, u32> = bits!(static Lsb0, u32; 1, 0, 1, 1, 0); | ||
| let _: &'static BitSlice = bits!(static 1, 0, 1, 1, 0); | ||
| } | ||
| #[test] | ||
| fn compile_bitarr() { | ||
@@ -102,3 +158,3 @@ let uint: BitArray<Lsb0, [u8; 1]> = bitarr![Lsb0, u8; 1, 0, 1, 0]; | ||
| assert_eq!(f, h); | ||
| assert_eq!(h.as_slice(), [!0u8; 13]); | ||
| assert_eq!(h.as_raw_slice(), [!0u8; 13]); | ||
@@ -518,9 +574,8 @@ let i: &mut BitSlice<Lsb0, usize> = bits![mut 1, 0, 1]; | ||
| // `__make_elem!` is only called after `$ord` has already been made opaque | ||
| // to matchers as a single `:tt`. Calling it directly with a path will fail | ||
| // the `:tt`, so this macro wraps it as one and forwards the rest. | ||
| // `__make_elem!` is only called after `$ord` has already been made | ||
| // opaque to matchers as a single `:tt`. Calling it directly with a path | ||
| // will fail the `:tt`, so this macro wraps it as one and forwards the | ||
| // rest. | ||
| macro_rules! invoke_make_elem { | ||
| ($ord:path, $($rest:tt)*) => { | ||
| __make_elem!($ord, $($rest)*) | ||
| }; | ||
| ($ord:path, $($rest:tt)*) => { __make_elem!($ord, $($rest)*) }; | ||
| } | ||
@@ -527,0 +582,0 @@ let uint: usize = |
+1
-13
@@ -22,3 +22,2 @@ /*! Memory element descriptions. | ||
| use funty::IsUnsigned; | ||
| use radium::marker::BitOps; | ||
@@ -36,13 +35,2 @@ | ||
| pub trait BitMemory: IsUnsigned + seal::Sealed { | ||
| /// The bit width of the integer. | ||
| /// | ||
| /// [`mem::size_of`] returns the size in bytes, and bytes are always eight | ||
| /// bits wide on architectures that Rust targets. | ||
| /// | ||
| /// Issue #76904 will place this constant on the fundamental integers | ||
| /// directly, as a `u32`. | ||
| /// | ||
| /// [`mem::size_of`]: core::mem::size_of | ||
| const BITS: u8 = mem::size_of::<Self>() as u8 * 8; | ||
| /// The number of bits required to store an index in the range `0 .. BITS`. | ||
@@ -53,3 +41,3 @@ const INDX: u8 = Self::BITS.trailing_zeros() as u8; | ||
| /// This is the value with the least significant `INDX`-many bits set high. | ||
| const MASK: u8 = Self::BITS - 1; | ||
| const MASK: u8 = Self::BITS as u8 - 1; | ||
| } | ||
@@ -56,0 +44,0 @@ |
+4
-5
@@ -291,3 +291,3 @@ /*! Ordering of bits within register elements. | ||
| let ct = upto - from; | ||
| if ct == R::BITS { | ||
| if ct == R::BITS as u8 { | ||
| return BitMask::ALL; | ||
@@ -340,3 +340,3 @@ } | ||
| let ct = upto - from; | ||
| if ct == R::BITS { | ||
| if ct == R::BITS as u8 { | ||
| return BitMask::ALL; | ||
@@ -362,3 +362,2 @@ } | ||
| pub use self::Lsb0 as LocalBits; | ||
| /** A default bit ordering. | ||
@@ -453,3 +452,3 @@ | ||
| for n in 0 .. R::BITS { | ||
| for n in 0 .. R::BITS as u8 { | ||
| // Wrap the counter as an index. | ||
@@ -473,3 +472,3 @@ let idx = unsafe { BitIdx::<R>::new_unchecked(n) }; | ||
| assert!( | ||
| pos.value() < R::BITS, | ||
| pos.value() < R::BITS as u8, | ||
| "Error when verifying the implementation of `BitOrder` for `{}`: \ | ||
@@ -476,0 +475,0 @@ Index {} produces a bit position ({}) that exceeds the type width \ |
+1
-1
@@ -28,4 +28,4 @@ /*! [`bitvec`] symbol export. | ||
| view::BitView, | ||
| BitArr, | ||
| }; | ||
| #[cfg(feature = "alloc")] | ||
@@ -32,0 +32,0 @@ pub use crate::{ |
+5
-6
@@ -82,2 +82,7 @@ /*! Mirror of the [`core::ptr`] module and `bitvec`-specific pointer structures. | ||
| use core::hash::{ | ||
| Hash, | ||
| Hasher, | ||
| }; | ||
| use crate::{ | ||
@@ -89,7 +94,2 @@ order::BitOrder, | ||
| use core::hash::{ | ||
| Hash, | ||
| Hasher, | ||
| }; | ||
| mod address; | ||
@@ -102,3 +102,2 @@ mod proxy; | ||
| pub(crate) use self::span::BitSpan; | ||
| pub use crate::{ | ||
@@ -105,0 +104,0 @@ mutability::{ |
+10
-10
| //! Non-null, well-aligned, `BitStore` addresses with limited casting capability | ||
| use crate::{ | ||
| mem::BitMemory, | ||
| mutability::{ | ||
| Const, | ||
| Mut, | ||
| Mutability, | ||
| }, | ||
| store::BitStore, | ||
| }; | ||
| use core::{ | ||
@@ -41,2 +31,12 @@ any::{ | ||
| use crate::{ | ||
| mem::BitMemory, | ||
| mutability::{ | ||
| Const, | ||
| Mut, | ||
| Mutability, | ||
| }, | ||
| store::BitStore, | ||
| }; | ||
| /** A non-null, well-aligned, `BitStore` element address. | ||
@@ -43,0 +43,0 @@ |
+16
-15
@@ -12,16 +12,2 @@ /*! Proxy reference for `&mut bool`. | ||
| use crate::{ | ||
| mutability::{ | ||
| Const, | ||
| Mut, | ||
| Mutability, | ||
| }, | ||
| order::{ | ||
| BitOrder, | ||
| Lsb0, | ||
| }, | ||
| ptr::BitPtr, | ||
| store::BitStore, | ||
| }; | ||
| use core::{ | ||
@@ -51,2 +37,16 @@ any::TypeId, | ||
| use crate::{ | ||
| mutability::{ | ||
| Const, | ||
| Mut, | ||
| Mutability, | ||
| }, | ||
| order::{ | ||
| BitOrder, | ||
| Lsb0, | ||
| }, | ||
| ptr::BitPtr, | ||
| store::BitStore, | ||
| }; | ||
| /** A proxy reference, equivalent to C++ [`std::bitset<N>::reference`]. | ||
@@ -551,6 +551,7 @@ | ||
| fn format() { | ||
| use crate::order::Msb0; | ||
| #[cfg(not(feature = "std"))] | ||
| use alloc::format; | ||
| use crate::order::Msb0; | ||
| let bits = bits![mut Msb0, u8; 0]; | ||
@@ -557,0 +558,0 @@ let mut bit = bits.get_mut(0).unwrap(); |
+15
-14
| //! Implementation of `Range<BitPtr>`. | ||
| use crate::{ | ||
| mutability::Mutability, | ||
| order::{ | ||
| BitOrder, | ||
| Lsb0, | ||
| }, | ||
| ptr::{ | ||
| BitPtr, | ||
| BitSpan, | ||
| }, | ||
| store::BitStore, | ||
| }; | ||
| use core::{ | ||
@@ -36,2 +23,15 @@ any::TypeId, | ||
| use crate::{ | ||
| mutability::Mutability, | ||
| order::{ | ||
| BitOrder, | ||
| Lsb0, | ||
| }, | ||
| ptr::{ | ||
| BitPtr, | ||
| BitSpan, | ||
| }, | ||
| store::BitStore, | ||
| }; | ||
| /** Equivalent to `Range<BitPtr<M, O, T>>`. | ||
@@ -436,2 +436,4 @@ | ||
| mod tests { | ||
| use core::mem::size_of; | ||
| use super::*; | ||
@@ -442,3 +444,2 @@ use crate::{ | ||
| }; | ||
| use core::mem::size_of; | ||
@@ -445,0 +446,0 @@ #[test] |
+33
-32
| //! A pointer to a single bit. | ||
| use core::{ | ||
| any::{ | ||
| type_name, | ||
| TypeId, | ||
| }, | ||
| cmp, | ||
| convert::{ | ||
| Infallible, | ||
| TryFrom, | ||
| TryInto, | ||
| }, | ||
| fmt::{ | ||
| self, | ||
| Debug, | ||
| Display, | ||
| Formatter, | ||
| Pointer, | ||
| }, | ||
| hash::{ | ||
| Hash, | ||
| Hasher, | ||
| }, | ||
| marker::PhantomData, | ||
| ptr, | ||
| }; | ||
| use funty::IsNumber; | ||
| use wyz::fmt::FmtForward; | ||
| use crate::{ | ||
@@ -9,3 +38,2 @@ access::BitAccess, | ||
| }, | ||
| mem::BitMemory, | ||
| mutability::{ | ||
@@ -31,30 +59,2 @@ Const, | ||
| use wyz::fmt::FmtForward; | ||
| use core::{ | ||
| any::{ | ||
| type_name, | ||
| TypeId, | ||
| }, | ||
| cmp, | ||
| convert::{ | ||
| Infallible, | ||
| TryFrom, | ||
| TryInto, | ||
| }, | ||
| fmt::{ | ||
| self, | ||
| Debug, | ||
| Display, | ||
| Formatter, | ||
| Pointer, | ||
| }, | ||
| hash::{ | ||
| Hash, | ||
| Hasher, | ||
| }, | ||
| marker::PhantomData, | ||
| ptr, | ||
| }; | ||
| /** Pointer to an individual bit in a memory element. Analagous to `*bool`. | ||
@@ -608,3 +608,3 @@ | ||
| // Pointers step by `T`, but **address values** step by `u8`. | ||
| .wrapping_mul(<u8 as BitMemory>::BITS as usize) | ||
| .wrapping_mul(<u8 as IsNumber>::BITS as usize) | ||
| // `self.head` moves the end farther from origin, | ||
@@ -857,3 +857,3 @@ .wrapping_add(self.head.value() as usize) | ||
| pub fn align_offset(self, align: usize) -> usize { | ||
| let width = <T::Mem as BitMemory>::BITS as usize; | ||
| let width = <T::Mem as IsNumber>::BITS as usize; | ||
| match ( | ||
@@ -1527,6 +1527,7 @@ self.addr.to_const().align_offset(align), | ||
| fn format() { | ||
| use crate::order::Msb0; | ||
| #[cfg(not(feature = "std"))] | ||
| use alloc::format; | ||
| use crate::order::Msb0; | ||
| let base = 0u16; | ||
@@ -1533,0 +1534,0 @@ let bitptr = BitPtr::<_, Msb0, _>::from_ref(&base); |
+27
-26
| //! Encoded pointer to a span region. | ||
| #[cfg(any(feature = "alloc", test))] | ||
| use core::convert::TryInto; | ||
| use core::{ | ||
| any, | ||
| convert::Infallible, | ||
| fmt::{ | ||
| self, | ||
| Debug, | ||
| Display, | ||
| Formatter, | ||
| Pointer, | ||
| }, | ||
| marker::PhantomData, | ||
| ptr::{ | ||
| self, | ||
| NonNull, | ||
| }, | ||
| }; | ||
| use funty::IsNumber; | ||
| use wyz::fmt::FmtForward; | ||
| use crate::{ | ||
@@ -28,24 +50,2 @@ domain::Domain, | ||
| use core::{ | ||
| any, | ||
| convert::Infallible, | ||
| fmt::{ | ||
| self, | ||
| Debug, | ||
| Display, | ||
| Formatter, | ||
| Pointer, | ||
| }, | ||
| marker::PhantomData, | ||
| ptr::{ | ||
| self, | ||
| NonNull, | ||
| }, | ||
| }; | ||
| use wyz::fmt::FmtForward; | ||
| #[cfg(any(feature = "alloc", test))] | ||
| use core::convert::TryInto; | ||
| /** Encoded handle to a bit-precision memory region. | ||
@@ -1159,2 +1159,7 @@ | ||
| mod tests { | ||
| use core::{ | ||
| mem, | ||
| ptr, | ||
| }; | ||
| use super::*; | ||
@@ -1165,6 +1170,2 @@ use crate::{ | ||
| }; | ||
| use core::{ | ||
| mem, | ||
| ptr, | ||
| }; | ||
@@ -1171,0 +1172,0 @@ #[test] |
+4
-4
| #![cfg(test)] | ||
| use core::cell::Cell; | ||
| use static_assertions::assert_not_impl_any; | ||
| use crate::{ | ||
@@ -13,6 +17,2 @@ mutability::Const, | ||
| use core::cell::Cell; | ||
| use static_assertions::assert_not_impl_any; | ||
| #[test] | ||
@@ -19,0 +19,0 @@ fn pointers_not_send_sync() { |
+21
-25
@@ -37,18 +37,2 @@ /*! [`serde`]-powered de/serialization. | ||
| use crate::{ | ||
| array::BitArray, | ||
| domain::Domain, | ||
| mem::BitMemory, | ||
| order::BitOrder, | ||
| ptr::{ | ||
| AddressError, | ||
| BitPtr, | ||
| BitPtrError, | ||
| BitSpanError, | ||
| }, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| use core::{ | ||
@@ -64,2 +48,3 @@ cmp, | ||
| use funty::IsNumber; | ||
| use serde::{ | ||
@@ -82,5 +67,18 @@ de::{ | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| use crate::{ | ||
| array::BitArray, | ||
| domain::Domain, | ||
| order::BitOrder, | ||
| ptr::{ | ||
| AddressError, | ||
| BitPtr, | ||
| BitPtrError, | ||
| BitSpanError, | ||
| }, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| #[cfg(feature = "alloc")] | ||
@@ -389,11 +387,3 @@ use crate::{ | ||
| mod tests { | ||
| use crate::prelude::*; | ||
| use serde::Deserialize; | ||
| use serde_test::{ | ||
| assert_ser_tokens, | ||
| Token, | ||
| }; | ||
| #[cfg(feature = "alloc")] | ||
@@ -404,3 +394,9 @@ use serde_test::{ | ||
| }; | ||
| use serde_test::{ | ||
| assert_ser_tokens, | ||
| Token, | ||
| }; | ||
| use crate::prelude::*; | ||
| macro_rules! bvtok { | ||
@@ -407,0 +403,0 @@ ( s $elts:expr, $head:expr, $bits:expr, $ty:ident $( , $data:expr )* ) => { |
+11
-11
| //! Port of the `[T]` operator implementations. | ||
| use crate::{ | ||
| access::BitAccess, | ||
| domain::DomainMut, | ||
| order::BitOrder, | ||
| slice::{ | ||
| BitSlice, | ||
| BitSliceIndex, | ||
| }, | ||
| store::BitStore, | ||
| }; | ||
| use core::ops::{ | ||
@@ -29,2 +18,13 @@ BitAndAssign, | ||
| use crate::{ | ||
| access::BitAccess, | ||
| domain::DomainMut, | ||
| order::BitOrder, | ||
| slice::{ | ||
| BitSlice, | ||
| BitSliceIndex, | ||
| }, | ||
| store::BitStore, | ||
| }; | ||
| impl<O, T, Rhs> BitAndAssign<Rhs> for BitSlice<O, T> | ||
@@ -31,0 +31,0 @@ where |
@@ -11,2 +11,9 @@ /*! Specialization overrides. | ||
| use core::ops::RangeBounds; | ||
| use funty::{ | ||
| IsInteger, | ||
| IsNumber, | ||
| }; | ||
| use crate::{ | ||
@@ -16,3 +23,2 @@ devel as dvl, | ||
| field::BitField, | ||
| mem::BitMemory, | ||
| order::{ | ||
@@ -27,6 +33,2 @@ BitOrder, | ||
| use core::ops::RangeBounds; | ||
| use funty::IsInteger; | ||
| /** Order-specialized function implementations. | ||
@@ -52,3 +54,3 @@ | ||
| let chunk_size = <usize as BitMemory>::BITS as usize; | ||
| let chunk_size = <usize as IsNumber>::BITS as usize; | ||
| for (to, from) in unsafe { self.chunks_mut(chunk_size).remove_alias() } | ||
@@ -94,3 +96,3 @@ .zip(src.chunks(chunk_size)) | ||
| let to: *mut Self = self.get_unchecked_mut(dest) as *mut _; | ||
| let chunk_size = <usize as BitMemory>::BITS as usize; | ||
| let chunk_size = <usize as IsNumber>::BITS as usize; | ||
| if rev { | ||
@@ -121,3 +123,3 @@ for (src, dst) in (&*from) | ||
| } | ||
| let chunk_size = <usize as BitMemory>::BITS as usize; | ||
| let chunk_size = <usize as IsNumber>::BITS as usize; | ||
| self.chunks(chunk_size) | ||
@@ -179,8 +181,8 @@ .zip(other.chunks(chunk_size)) | ||
| 0 => return None, | ||
| n => n, | ||
| n => n - 1, | ||
| }; | ||
| (|| match self.domain() { | ||
| match self.domain() { | ||
| Domain::Enclave { head, elem, tail } => { | ||
| let val = (Lsb0::mask(head, tail) & elem.load_value()).value(); | ||
| let dead_bits = T::Mem::BITS - tail.value(); | ||
| let dead_bits = T::Mem::BITS as u8 - tail.value(); | ||
| if val != T::Mem::ZERO { | ||
@@ -223,4 +225,3 @@ out -= val.leading_zeros() as usize - dead_bits as usize; | ||
| }, | ||
| })() | ||
| .map(|idx| idx - 1) | ||
| } | ||
| } | ||
@@ -279,8 +280,8 @@ | ||
| 0 => return None, | ||
| n => n, | ||
| n => n - 1, | ||
| }; | ||
| (|| match self.domain() { | ||
| match self.domain() { | ||
| Domain::Enclave { head, elem, tail } => { | ||
| let val = (Lsb0::mask(head, tail) & !elem.load_value()).value(); | ||
| let dead_bits = T::Mem::BITS - tail.value(); | ||
| let dead_bits = T::Mem::BITS as u8 - tail.value(); | ||
| if val != T::Mem::ZERO { | ||
@@ -323,4 +324,3 @@ out -= val.leading_zeros() as usize - dead_bits as usize; | ||
| }, | ||
| })() | ||
| .map(|idx| idx - 1) | ||
| } | ||
| } | ||
@@ -349,3 +349,3 @@ } | ||
| let chunk_size = <usize as BitMemory>::BITS as usize; | ||
| let chunk_size = <usize as IsNumber>::BITS as usize; | ||
| for (to, from) in unsafe { self.chunks_mut(chunk_size).remove_alias() } | ||
@@ -373,3 +373,3 @@ .zip(src.chunks(chunk_size)) | ||
| let to: *mut Self = self.get_unchecked_mut(dest) as *mut _; | ||
| let chunk_size = <usize as BitMemory>::BITS as usize; | ||
| let chunk_size = <usize as IsNumber>::BITS as usize; | ||
| if rev { | ||
@@ -400,3 +400,3 @@ for (src, dst) in (&*from) | ||
| } | ||
| let chunk_size = <usize as BitMemory>::BITS as usize; | ||
| let chunk_size = <usize as IsNumber>::BITS as usize; | ||
| self.chunks(chunk_size) | ||
@@ -463,3 +463,3 @@ .zip(other.chunks(chunk_size)) | ||
| let val = (Msb0::mask(head, tail) & elem.load_value()).value(); | ||
| let dead_bits = T::Mem::BITS - tail.value(); | ||
| let dead_bits = T::Mem::BITS as u8 - tail.value(); | ||
| if val != T::Mem::ZERO { | ||
@@ -560,3 +560,3 @@ out -= val.trailing_zeros() as usize - dead_bits as usize; | ||
| let val = (Msb0::mask(head, tail) & !elem.load_value()).value(); | ||
| let dead_bits = T::Mem::BITS - tail.value(); | ||
| let dead_bits = T::Mem::BITS as u8 - tail.value(); | ||
| if val != T::Mem::ZERO { | ||
@@ -563,0 +563,0 @@ out -= val.trailing_zeros() as usize - dead_bits as usize; |
@@ -5,6 +5,6 @@ //! Unit tests for the `slice` module. | ||
| use tap::conv::TryConv; | ||
| use crate::prelude::*; | ||
| use tap::conv::TryConv; | ||
| #[test] | ||
@@ -867,7 +867,7 @@ fn construction() { | ||
| mod format { | ||
| use crate::prelude::*; | ||
| #[cfg(not(feature = "std"))] | ||
| use alloc::format; | ||
| use crate::prelude::*; | ||
| #[test] | ||
@@ -874,0 +874,0 @@ fn binary() { |
+16
-18
| //! Non-operator trait implementations. | ||
| use crate::{ | ||
| domain::Domain, | ||
| mem::BitMemory, | ||
| order::{ | ||
| BitOrder, | ||
| Lsb0, | ||
| Msb0, | ||
| }, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| #[cfg(feature = "alloc")] | ||
| use alloc::borrow::ToOwned; | ||
| use core::{ | ||
@@ -37,2 +26,3 @@ any::TypeId, | ||
| use funty::IsNumber; | ||
| use tap::pipe::Pipe; | ||
@@ -42,6 +32,14 @@ | ||
| use crate::vec::BitVec; | ||
| use crate::{ | ||
| domain::Domain, | ||
| order::{ | ||
| BitOrder, | ||
| Lsb0, | ||
| Msb0, | ||
| }, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| view::BitView, | ||
| }; | ||
| #[cfg(feature = "alloc")] | ||
| use alloc::borrow::ToOwned; | ||
| impl<O, T> Eq for BitSlice<O, T> | ||
@@ -393,5 +391,5 @@ where | ||
| */ | ||
| const D: usize = <usize as BitMemory>::BITS as usize / $blksz; | ||
| const D: usize = <usize as IsNumber>::BITS as usize / $blksz; | ||
| #[allow(clippy::modulo_one)] | ||
| const M: usize = <usize as BitMemory>::BITS as usize % $blksz; | ||
| const M: usize = <usize as IsNumber>::BITS as usize % $blksz; | ||
| const W: usize = D + (M != 0) as usize; | ||
@@ -398,0 +396,0 @@ let mut w: [u8; W + 2] = [b'0'; W + 2]; |
+11
-9
@@ -83,2 +83,9 @@ /*! Memory modeling. | ||
| use core::{ | ||
| cell::Cell, | ||
| fmt::Debug, | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| use crate::{ | ||
@@ -97,9 +104,2 @@ access::*, | ||
| use core::{ | ||
| cell::Cell, | ||
| fmt::Debug, | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| /** Common interface for memory regions. | ||
@@ -380,7 +380,9 @@ | ||
| mod tests { | ||
| use super::*; | ||
| use crate::prelude::*; | ||
| use core::cell::Cell; | ||
| use static_assertions::*; | ||
| use super::*; | ||
| use crate::prelude::*; | ||
| #[test] | ||
@@ -387,0 +389,0 @@ fn load_store() { |
+72
-22
@@ -24,2 +24,22 @@ /*! A dynamically-allocated buffer containing a [`BitSlice`] region. | ||
| #[cfg(not(feature = "std"))] | ||
| use alloc::vec; | ||
| use alloc::vec::Vec; | ||
| use core::{ | ||
| mem::{ | ||
| self, | ||
| ManuallyDrop, | ||
| }, | ||
| slice, | ||
| }; | ||
| use funty::{ | ||
| IsInteger, | ||
| IsNumber, | ||
| }; | ||
| use tap::{ | ||
| pipe::Pipe, | ||
| tap::Tap, | ||
| }; | ||
| use crate::{ | ||
@@ -29,6 +49,3 @@ boxed::BitBox, | ||
| index::BitIdx, | ||
| mem::{ | ||
| BitMemory, | ||
| BitRegister, | ||
| }, | ||
| mem::BitRegister, | ||
| mutability::{ | ||
@@ -45,2 +62,3 @@ Const, | ||
| BitSpan, | ||
| BitSpanError, | ||
| }, | ||
@@ -51,19 +69,2 @@ slice::BitSlice, | ||
| use alloc::vec::Vec; | ||
| use core::{ | ||
| mem::{ | ||
| self, | ||
| ManuallyDrop, | ||
| }, | ||
| slice, | ||
| }; | ||
| use funty::IsInteger; | ||
| use tap::{ | ||
| pipe::Pipe, | ||
| tap::Tap, | ||
| }; | ||
| /** A contiguous growable array of bits. | ||
@@ -326,3 +327,3 @@ | ||
| /// assert_eq!(bv, bits[2 ..]); | ||
| /// assert_eq!(bits.as_slice(), bv.as_raw_slice()); | ||
| /// assert_eq!(bits.as_raw_slice(), bv.as_raw_slice()); | ||
| /// ``` | ||
@@ -363,2 +364,51 @@ /// | ||
| /// Constructs a new `BitVec` from the bit-pattern of a single element. | ||
| /// | ||
| /// This function copies `elem` into a new vector, then views that vector as | ||
| /// bits. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ```rust | ||
| /// use bitvec::prelude::*; | ||
| /// | ||
| /// assert_eq!(BitVec::<Msb0, _>::from_element(0xABBAu16).count_ones(), 10); | ||
| /// ``` | ||
| #[inline] | ||
| pub fn from_element(elem: T) -> Self { | ||
| vec![elem].pipe(Self::from_vec) | ||
| } | ||
| /// Constructs a new `BitVec` from the bit-pattern of an element slice. | ||
| /// | ||
| /// This function copies `slice` into a new vector, then views that vector | ||
| /// as bits. | ||
| /// | ||
| /// # Parameters | ||
| /// | ||
| /// - `slice`: A slice of elements. It should not exceed [`BitSlice::<O, | ||
| /// T>::MAX_ELTS`]. | ||
| /// | ||
| /// # Returns | ||
| /// | ||
| /// This returns an error if [`BitSlice::<O, T>::from_slice`] fails; | ||
| /// otherwise, it returns the newly allocated and initialized bit-vector. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ```rust | ||
| /// use bitvec::prelude::*; | ||
| /// | ||
| /// let slice = &[0u8, 1, 2, 3]; | ||
| /// let bv = BitVec::<Lsb0, _>::from_slice(slice); | ||
| /// assert!(bv.is_ok()); | ||
| /// assert_eq!(bv.unwrap().len(), 32); | ||
| /// ``` | ||
| /// | ||
| /// [`BitSlice::<O, T>::MAX_ELTS`]: crate::slice::BitSlice::MAX_ELTS | ||
| /// [`BitSlice::<O, T>::from_slice`]: crate::slice::BitSlice::from_slice | ||
| pub fn from_slice(slice: &[T]) -> Result<Self, BitSpanError<T>> { | ||
| slice.pipe(BitSlice::from_slice).map(Self::from_bitslice) | ||
| } | ||
| /// Converts a [`Vec<T>`] into a `BitVec<O, T>` without copying its buffer. | ||
@@ -365,0 +415,0 @@ /// |
+18
-19
| //! Port of the `Vec<T>` inherent API. | ||
| use alloc::vec::Vec; | ||
| use core::{ | ||
| mem::{ | ||
| self, | ||
| ManuallyDrop, | ||
| }, | ||
| ops::RangeBounds, | ||
| }; | ||
| use funty::IsNumber; | ||
| use tap::pipe::Pipe; | ||
| use crate::{ | ||
| boxed::BitBox, | ||
| index::BitTail, | ||
| mem::BitMemory, | ||
| mutability::{ | ||
@@ -28,14 +39,2 @@ Const, | ||
| use alloc::vec::Vec; | ||
| use core::{ | ||
| mem::{ | ||
| self, | ||
| ManuallyDrop, | ||
| }, | ||
| ops::RangeBounds, | ||
| }; | ||
| use tap::pipe::Pipe; | ||
| /// Port of the `Vec<T>` inherent API. | ||
@@ -593,3 +592,3 @@ impl<O, T> BitVec<O, T> | ||
| pub fn swap_remove(&mut self, index: usize) -> bool { | ||
| self.assert_in_bounds(index); | ||
| self.assert_in_bounds(index, 0 .. self.len()); | ||
| let last = self.len() - 1; | ||
@@ -620,10 +619,10 @@ unsafe { | ||
| /// let mut bv = bitvec![0; 5]; | ||
| /// bv.insert(4, true); | ||
| /// assert_eq!(bv, bits![0, 0, 0, 0, 1, 0]); | ||
| /// bv.insert(5, true); | ||
| /// assert_eq!(bv, bits![0, 0, 0, 0, 0, 1]); | ||
| /// bv.insert(2, true); | ||
| /// assert_eq!(bv, bits![0, 0, 1, 0, 0, 1, 0]); | ||
| /// assert_eq!(bv, bits![0, 0, 1, 0, 0, 0, 1]); | ||
| /// ``` | ||
| #[inline] | ||
| pub fn insert(&mut self, index: usize, value: bool) { | ||
| self.assert_in_bounds(index); | ||
| self.assert_in_bounds(index, 0 ..= self.len()); | ||
| self.push(value); | ||
@@ -655,3 +654,3 @@ unsafe { self.get_unchecked_mut(index ..) }.rotate_right(1); | ||
| pub fn remove(&mut self, index: usize) -> bool { | ||
| self.assert_in_bounds(index); | ||
| self.assert_in_bounds(index, 0 .. self.len()); | ||
| let last = self.len() - 1; | ||
@@ -658,0 +657,0 @@ unsafe { |
+13
-14
| //! Iterators over `Vec<T>`. | ||
| use crate::{ | ||
| devel as dvl, | ||
| mutability::Mutability, | ||
| order::BitOrder, | ||
| ptr::BitRef, | ||
| slice::{ | ||
| BitSlice, | ||
| Iter, | ||
| }, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| use alloc::vec::Vec; | ||
| use core::{ | ||
@@ -47,2 +33,15 @@ fmt::{ | ||
| use crate::{ | ||
| devel as dvl, | ||
| mutability::Mutability, | ||
| order::BitOrder, | ||
| ptr::BitRef, | ||
| slice::{ | ||
| BitSlice, | ||
| Iter, | ||
| }, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| impl<O, T> Extend<bool> for BitVec<O, T> | ||
@@ -49,0 +48,0 @@ where |
+7
-7
| //! Port of the `Vec<T>` operator implementations. | ||
| use crate::{ | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| use core::{ | ||
@@ -27,2 +20,9 @@ mem::ManuallyDrop, | ||
| use crate::{ | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| impl<O, T, Rhs> BitAnd<Rhs> for BitVec<O, T> | ||
@@ -29,0 +29,0 @@ where |
+14
-11
| #![cfg(test)] | ||
| use crate::prelude::*; | ||
| #[cfg(not(feature = "std"))] | ||
| use alloc::{ | ||
| format, | ||
| vec, | ||
| vec::Vec, | ||
| }; | ||
| use core::{ | ||
@@ -14,13 +18,7 @@ borrow::{ | ||
| }; | ||
| #[cfg(not(feature = "std"))] | ||
| use alloc::{ | ||
| format, | ||
| vec, | ||
| vec::Vec, | ||
| }; | ||
| #[cfg(feature = "std")] | ||
| use std::panic::catch_unwind; | ||
| use crate::prelude::*; | ||
| #[test] | ||
@@ -219,2 +217,6 @@ fn from_vec() { | ||
| fn misc() { | ||
| let mut bv = bitvec![0; 0]; | ||
| bv.insert(0, true); | ||
| assert_eq!(bv, bits![1]); | ||
| let mut bv = bitvec![1; 10]; | ||
@@ -245,4 +247,4 @@ bv.truncate(20); | ||
| let mut bv_3 = bv_1.clone(); | ||
| bv_1.append(&mut bv_2); | ||
| assert_eq!(bv_1, bits![0, 0, 0, 0, 0, 1, 1, 1, 1, 1]); | ||
@@ -253,2 +255,3 @@ assert!(bv_2.is_empty()); | ||
| assert_eq!(bv_1, bits![0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]); | ||
| assert!(bv_3.is_empty()); | ||
@@ -255,0 +258,0 @@ let bv_4 = bv_1.split_off(5); |
| //! Non-operator trait implementations. | ||
| use crate::{ | ||
| boxed::BitBox, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| use alloc::vec::Vec; | ||
| use core::{ | ||
@@ -38,2 +29,10 @@ borrow::{ | ||
| use crate::{ | ||
| boxed::BitBox, | ||
| order::BitOrder, | ||
| slice::BitSlice, | ||
| store::BitStore, | ||
| vec::BitVec, | ||
| }; | ||
| impl<O, T> Borrow<BitSlice<O, T>> for BitVec<O, T> | ||
@@ -40,0 +39,0 @@ where |
+4
-5
@@ -32,7 +32,6 @@ /*! [`BitSlice`] view adapters for memory regions. | ||
| use funty::IsNumber; | ||
| use crate::{ | ||
| mem::{ | ||
| BitMemory, | ||
| BitRegister, | ||
| }, | ||
| mem::BitRegister, | ||
| order::BitOrder, | ||
@@ -110,3 +109,3 @@ ptr::BitPtr, | ||
| Self::const_elts() | ||
| * <<Self::Store as BitStore>::Mem as BitMemory>::BITS as usize | ||
| * <<Self::Store as BitStore>::Mem as IsNumber>::BITS as usize | ||
| } | ||
@@ -113,0 +112,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display