add basic tinyptr code
This commit is contained in:
parent
c0fcfe9dbb
commit
3a3162a1a3
9 changed files with 440 additions and 15 deletions
15
.drone.yml
15
.drone.yml
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: notify-hydra
|
||||
|
||||
steps:
|
||||
- name: Notify hydra
|
||||
image: nixery.dev/shell/curl
|
||||
commands:
|
||||
- curl --get --data-urlencode "jobsets=darkkirb:rkb1-firmware" https://hydra.chir.rs/api/push
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
branch:
|
||||
- main
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -565,6 +565,10 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyptr"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
args@{
|
||||
release ? true,
|
||||
rootFeatures ? [
|
||||
"tinyptr/default"
|
||||
"rkbfirm/default"
|
||||
],
|
||||
rustPackages,
|
||||
|
@ -41,6 +42,7 @@ in
|
|||
{
|
||||
cargo2nixVersion = "0.11.0";
|
||||
workspace = {
|
||||
tinyptr = rustPackages.unknown.tinyptr."0.1.0";
|
||||
rkbfirm = rustPackages.unknown.rkbfirm."0.1.0";
|
||||
};
|
||||
"registry+https://github.com/rust-lang/crates.io-index".aho-corasick."0.7.18" = overridableMkRustCrate (profileName: rec {
|
||||
|
@ -801,6 +803,13 @@ in
|
|||
};
|
||||
});
|
||||
|
||||
"unknown".tinyptr."0.1.0" = overridableMkRustCrate (profileName: rec {
|
||||
name = "tinyptr";
|
||||
version = "0.1.0";
|
||||
registry = "unknown";
|
||||
src = fetchCrateLocal (workspaceSrc + "/lib/tinyptr");
|
||||
});
|
||||
|
||||
"registry+https://github.com/rust-lang/crates.io-index".unicode-ident."1.0.1" = overridableMkRustCrate (profileName: rec {
|
||||
name = "unicode-ident";
|
||||
version = "1.0.1";
|
||||
|
|
|
@ -3,6 +3,10 @@ name = "rkbfirm"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"lib/tinyptr"
|
||||
]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
cargo2nix.packages.${system}.cargo2nix
|
||||
elf2uf2-rs
|
||||
cargo-embed
|
||||
llvmPackages_latest.bintools
|
||||
];
|
||||
};
|
||||
packages = rec {
|
||||
|
|
8
lib/tinyptr/Cargo.toml
Normal file
8
lib/tinyptr/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "tinyptr"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
123
lib/tinyptr/src/lib.rs
Normal file
123
lib/tinyptr/src/lib.rs
Normal file
|
@ -0,0 +1,123 @@
|
|||
//! 16 bit pointer library
|
||||
//!
|
||||
//! This library provides small pointers with a range of 64 kiB. This is useful for memory-limited
|
||||
//! microcontrollers.
|
||||
//!
|
||||
//! It uses a const generic parameter to set the base address of the pointer. This allows multiple
|
||||
//! small memory pools to coexist.
|
||||
#![feature(coerce_unsized)]
|
||||
#![feature(mixed_integer_ops)]
|
||||
#![feature(never_type)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(slice_ptr_len)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(unsize)]
|
||||
#![no_std]
|
||||
|
||||
use core::hash::Hash;
|
||||
|
||||
pub mod ptr;
|
||||
|
||||
/// Trait that defines valid destination types for a pointer.
|
||||
pub trait Pointable {
|
||||
/// The pointer metadata.
|
||||
type PointerMeta;
|
||||
/// The tiny version of the pointer metadata.
|
||||
type PointerMetaTiny: Copy + Eq + Ord + Hash;
|
||||
/// Conversion error.
|
||||
type ConversionError: core::fmt::Display + core::fmt::Debug + Clone;
|
||||
|
||||
/// Try reduce the pointer metadata to a tiny version.
|
||||
///
|
||||
/// # Errors
|
||||
/// This function returns an error if the pointer metadata does not fit into a tiny version.
|
||||
fn try_tiny(meta: Self::PointerMeta) -> Result<Self::PointerMetaTiny, Self::ConversionError>;
|
||||
/// Reduce the pointer metadata to a tiny version.
|
||||
///
|
||||
/// # Panics
|
||||
/// This function panics if it cannot convert the pointer metadata to a tiny version.
|
||||
fn tiny(meta: Self::PointerMeta) -> Self::PointerMetaTiny {
|
||||
Self::try_tiny(meta).unwrap()
|
||||
}
|
||||
/// Reduce the pointer metadata to a tiny version, without checking
|
||||
///
|
||||
/// # Safety
|
||||
/// This function is unsafe because it does not check if the pointer metadata fits into a tiny version.
|
||||
unsafe fn tiny_unchecked(meta: Self::PointerMeta) -> Self::PointerMetaTiny {
|
||||
Self::tiny(meta)
|
||||
}
|
||||
/// Convert a tiny version of the pointer metadata to the full version.
|
||||
fn huge(meta: Self::PointerMetaTiny) -> Self::PointerMeta;
|
||||
|
||||
/// Returns an address and the pointer metadata for a pointer
|
||||
fn extract_parts(ptr: *const Self) -> (usize, Self::PointerMeta);
|
||||
|
||||
/// Returns a pointer to an address in a specific address space
|
||||
fn create_ptr(base_ptr: *const (), address: usize, meta: Self::PointerMeta) -> *const Self;
|
||||
|
||||
/// Returns a mutable pointer to an address in a specific address space
|
||||
fn create_ptr_mut(base_ptr: *mut (), address: usize, meta: Self::PointerMeta) -> *mut Self;
|
||||
}
|
||||
|
||||
impl<T: Sized> Pointable for T {
|
||||
type PointerMeta = ();
|
||||
type PointerMetaTiny = ();
|
||||
type ConversionError = !;
|
||||
|
||||
fn try_tiny(_: ()) -> Result<(), !> {
|
||||
Ok(())
|
||||
}
|
||||
fn tiny(_: ()) -> () {}
|
||||
fn huge(_: ()) -> () {}
|
||||
|
||||
fn extract_parts(ptr: *const Self) -> (usize, ()) {
|
||||
(ptr.addr(), ())
|
||||
}
|
||||
fn create_ptr(base_ptr: *const (), address: usize, _: ()) -> *const Self {
|
||||
base_ptr.with_addr(address).cast()
|
||||
}
|
||||
fn create_ptr_mut(base_ptr: *mut (), address: usize, _: ()) -> *mut Self {
|
||||
base_ptr.with_addr(address).cast()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sized> Pointable for [T] {
|
||||
type PointerMeta = usize;
|
||||
type PointerMetaTiny = u16;
|
||||
type ConversionError = <u16 as TryFrom<usize>>::Error;
|
||||
|
||||
fn try_tiny(meta: usize) -> Result<u16, Self::ConversionError> {
|
||||
meta.try_into()
|
||||
}
|
||||
unsafe fn tiny_unchecked(meta: usize) -> u16 {
|
||||
meta as u16
|
||||
}
|
||||
fn huge(meta: u16) -> usize {
|
||||
meta.into()
|
||||
}
|
||||
fn extract_parts(ptr: *const Self) -> (usize, usize) {
|
||||
(ptr.as_ptr().addr(), ptr.len())
|
||||
}
|
||||
fn create_ptr(base_ptr: *const (), address: usize, meta: usize) -> *const Self {
|
||||
core::ptr::from_raw_parts(base_ptr.with_addr(address), meta)
|
||||
}
|
||||
fn create_ptr_mut(base_ptr: *mut (), address: usize, meta: usize) -> *mut Self {
|
||||
core::ptr::from_raw_parts_mut(base_ptr.with_addr(address), meta)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn base_ptr<const BASE: usize>() -> *const () {
|
||||
core::ptr::from_exposed_addr(BASE)
|
||||
}
|
||||
pub(crate) fn base_ptr_mut<const BASE: usize>() -> *mut () {
|
||||
core::ptr::from_exposed_addr_mut(BASE)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PointerConversionError<T: ?Sized + Pointable> {
|
||||
/// The pointer is not in 16 bit address space
|
||||
NotInAddressSpace(<u16 as TryFrom<usize>>::Error),
|
||||
/// The pointer metadata cannot be reduced in size
|
||||
CannotReduceMeta(<T as Pointable>::ConversionError),
|
||||
}
|
286
lib/tinyptr/src/ptr/const_ptr.rs
Normal file
286
lib/tinyptr/src/ptr/const_ptr.rs
Normal file
|
@ -0,0 +1,286 @@
|
|||
//! Constant pointer
|
||||
|
||||
use core::{marker::{PhantomData, Unsize}, ops::CoerceUnsized, cmp::Ordering, fmt, hash::{Hash, Hasher}};
|
||||
|
||||
use crate::{base_ptr, Pointable, PointerConversionError};
|
||||
|
||||
/// A tiny constant pointer
|
||||
pub struct ConstPtr<T: Pointable + ?Sized, const BASE: usize> {
|
||||
pub(crate) ptr: u16,
|
||||
pub(crate) meta: <T as Pointable>::PointerMetaTiny,
|
||||
pub(crate) _marker: PhantomData<*const T>,
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> ConstPtr<T, BASE> {
|
||||
/// Create a new constant pointer from raw parts
|
||||
pub const fn from_raw_parts(ptr: u16, meta: <T as Pointable>::PointerMetaTiny) -> Self {
|
||||
Self {
|
||||
ptr,
|
||||
meta,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
/// Creates a tiny pointer unchecked
|
||||
///
|
||||
/// # Safety
|
||||
/// This is unsafe because the address of the pointer may change.
|
||||
pub unsafe fn new_unchecked(ptr: *const T) -> Self {
|
||||
let (addr, meta) = T::extract_parts(ptr);
|
||||
let addr = if ptr.is_null() {
|
||||
0
|
||||
} else {
|
||||
addr.wrapping_sub(BASE)
|
||||
};
|
||||
Self::from_raw_parts(addr as u16, T::tiny_unchecked(meta))
|
||||
}
|
||||
/// Tries to create a tiny pointer from a pointer
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the pointer does not fit in the address space
|
||||
pub fn new(ptr: *const T) -> Result<Self, PointerConversionError<T>> {
|
||||
let (addr, meta) = T::extract_parts(ptr);
|
||||
let addr = if ptr.is_null() {
|
||||
0
|
||||
} else {
|
||||
addr.wrapping_sub(BASE)
|
||||
};
|
||||
let addr = addr
|
||||
.try_into()
|
||||
.map_err(PointerConversionError::NotInAddressSpace)?;
|
||||
let meta = T::try_tiny(meta).map_err(PointerConversionError::CannotReduceMeta)?;
|
||||
Ok(Self::from_raw_parts(addr, meta))
|
||||
}
|
||||
/// Widens the pointer
|
||||
pub fn wide(self) -> *const T {
|
||||
let addr = if self.ptr == 0 {
|
||||
0
|
||||
} else {
|
||||
usize::from(self.ptr).wrapping_add(BASE)
|
||||
};
|
||||
T::create_ptr(base_ptr::<BASE>(), addr, T::huge(self.meta))
|
||||
}
|
||||
/// Returns `true` if the pointer is null
|
||||
pub const fn is_null(self) -> bool {
|
||||
self.ptr == 0
|
||||
}
|
||||
/// Casts to a pointer of another type
|
||||
pub const fn cast<U: Pointable<PointerMetaTiny = ()>>(self) -> ConstPtr<U, BASE>
|
||||
where
|
||||
T: Pointable<PointerMetaTiny = ()>,
|
||||
{
|
||||
ConstPtr::from_raw_parts(self.ptr, self.meta)
|
||||
}
|
||||
/// Use the pointer value in a new pointer of another type
|
||||
pub const fn with_metadata_of<U: Pointable + ?Sized>(
|
||||
self,
|
||||
val: ConstPtr<U, BASE>,
|
||||
) -> ConstPtr<U, BASE> {
|
||||
ConstPtr::from_raw_parts(self.ptr, val.meta)
|
||||
}
|
||||
// TODO: as_mut
|
||||
/// Gets the address portion of the pointer
|
||||
pub const fn addr(self) -> u16
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.ptr
|
||||
}
|
||||
/// Gets the address portion of the pointer and exposeses the provenenance part
|
||||
pub const fn expose_addr(self) -> u16
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.ptr
|
||||
}
|
||||
/// Creates a new pointer with the given address
|
||||
pub const fn with_addr(self, addr: u16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
Self::from_raw_parts(addr, self.meta)
|
||||
}
|
||||
/// Creates a new pointer by mapping self’s address to a new one
|
||||
pub fn map_addr(self, f: impl FnOnce(u16) -> u16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.with_addr(f(self.addr()))
|
||||
}
|
||||
/// Decompose a pointer into its address and metadata
|
||||
pub fn to_raw_parts(self) -> (ConstPtr<(), BASE>, <T as Pointable>::PointerMetaTiny) {
|
||||
(ConstPtr::from_raw_parts(self.ptr, ()), self.meta)
|
||||
}
|
||||
// TODO: as_ref
|
||||
// TODO: as_ref_unchecked
|
||||
// TODO: as_uninit_ref
|
||||
/// Calculates the offset from a pointer
|
||||
pub const unsafe fn offset(self, count: i16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset(count)
|
||||
}
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic
|
||||
pub const fn wrapping_offset(mut self, count: i16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.ptr = self
|
||||
.ptr
|
||||
.wrapping_add_signed(count.wrapping_mul(core::mem::size_of::<T>() as i16));
|
||||
self
|
||||
}
|
||||
/// Calculates the distance between two pointers
|
||||
pub const unsafe fn offset_from(self, origin: Self) -> i16
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset_from(origin)
|
||||
}
|
||||
/// Calculates the distance between two pointers using wrapping arithmetic
|
||||
pub const fn wrapping_offset_from(self, origin: Self) -> i16
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
(origin.ptr as i16)
|
||||
.wrapping_sub(self.ptr as i16)
|
||||
.wrapping_div(core::mem::size_of::<T>() as i16)
|
||||
}
|
||||
/// calculates the distance between two pointers where it is known that self is equal or
|
||||
/// greater than origin
|
||||
pub unsafe fn sub_ptr(self, origin: Self) -> u16
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
u16::try_from(self.wrapping_offset_from(origin)).unwrap_unchecked()
|
||||
}
|
||||
/// Calculates the offset from a pointer
|
||||
pub const unsafe fn add(self, count: u16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.offset(count as i16)
|
||||
}
|
||||
/// Calculates the offset from a pointer
|
||||
pub const unsafe fn sub(self, count: u16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.offset((count as i16).wrapping_neg())
|
||||
}
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic
|
||||
pub const fn wrapping_add(self, count: u16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset(count as i16)
|
||||
}
|
||||
/// Calculates the offset from a pointer using wrapping arithmetic
|
||||
pub const fn wrapping_sub(self, count: u16) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wrapping_offset((count as i16).wrapping_neg())
|
||||
}
|
||||
/// Reads the value from self without moving it. this leaves the memory in self unchanged.
|
||||
pub unsafe fn read(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wide().read()
|
||||
}
|
||||
/// Performs a volatile read of the value from self without moving it. this leaves the memory in self unchanged.
|
||||
pub unsafe fn read_volatile(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wide().read_volatile()
|
||||
}
|
||||
/// Reads the value from self without moving it. this leaves the memory in self unchanged.
|
||||
pub unsafe fn read_unaligned(self) -> T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.wide().read_unaligned()
|
||||
}
|
||||
// TODO: copy_to
|
||||
// TODO: copy_to_nonoverlapping
|
||||
pub const fn align_offset(self, align: u16) -> u16
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
if !align.is_power_of_two() {
|
||||
panic!("align must be a power of two");
|
||||
}
|
||||
(self.ptr.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1))
|
||||
.wrapping_sub(self.ptr)
|
||||
.wrapping_div(core::mem::size_of::<T>() as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pointable<PointerMetaTiny = ()>, const BASE: usize> ConstPtr<[T], BASE> {
|
||||
pub const fn len(self) -> u16 {
|
||||
self.meta
|
||||
}
|
||||
pub const fn as_ptr(self) -> ConstPtr<T, BASE> {
|
||||
ConstPtr::from_raw_parts(self.ptr, ())
|
||||
}
|
||||
// TODO: as_uninit_slice
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> PartialEq for ConstPtr<T, BASE>
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(self.ptr == other.ptr) && (self.meta == other.meta)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> Eq for ConstPtr<T, BASE> {}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> Ord for ConstPtr<T, BASE>
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.ptr.cmp(&other.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> PartialOrd for ConstPtr<T, BASE>
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized + Unsize<U>, U: Pointable, const BASE: usize> CoerceUnsized<ConstPtr<U, BASE>> for ConstPtr<T, BASE>
|
||||
where <T as Pointable>::PointerMetaTiny: CoerceUnsized<<U as Pointable>::PointerMetaTiny>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> Clone for ConstPtr<T, BASE> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> Copy for ConstPtr<T, BASE> {}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> fmt::Debug for ConstPtr<T, BASE>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Pointer::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> Hash for ConstPtr<T, BASE> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
state.write_usize(BASE);
|
||||
state.write_u16(self.ptr);
|
||||
self.meta.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pointable + ?Sized, const BASE: usize> fmt::Pointer for ConstPtr<T, BASE>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Pointer::fmt(&self.wide(), f)
|
||||
}
|
||||
}
|
5
lib/tinyptr/src/ptr/mod.rs
Normal file
5
lib/tinyptr/src/ptr/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
//! Raw pointers
|
||||
|
||||
mod const_ptr;
|
||||
#[doc(inline)]
|
||||
pub use const_ptr::*;
|
Loading…
Reference in a new issue