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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
uses: actions/checkout@v4

- name: "Run Analyzer"
run: cargo check --all-features --all-targets --verbose --workspace
run: cargo check --all-targets --features libc --verbose --workspace

#
# A complete but basic build of the project, running on common x86-64 ubuntu
Expand All @@ -89,7 +89,7 @@ jobs:
uses: actions/checkout@v4

- name: "Build and Test"
run: cargo test --all-features --all-targets --verbose --workspace
run: cargo test --all-targets --features libc --verbose --workspace

#
# A simple no-op job that serves as guard. All extended jobs depend on this
Expand Down Expand Up @@ -124,7 +124,7 @@ jobs:
uses: actions/checkout@v4

- name: "Build and Test"
run: cargo test --all-features --all-targets --verbose --workspace
run: cargo test --all-targets --features libc --verbose --workspace

#
# A matrix of project builds with different settings. All builds run the
Expand All @@ -146,8 +146,8 @@ jobs:

# Explicitly set all options here to document them.
cargoargs: >-
--all-features
--all-targets
--features libc
--profile=release
image: "ghcr.io/readaheadeu/rae-ci-archlinux:latest"
toolchain: stable
Expand All @@ -157,8 +157,8 @@ jobs:
name: "Ubuntu-x86_64-nightly-release"

cargoargs: >-
--all-features
--all-targets
--features libc
--profile=release
image: "ghcr.io/readaheadeu/rae-ci-ubuntu:latest"
toolchain: nightly
Expand Down Expand Up @@ -204,8 +204,8 @@ jobs:
run: |
cargo \
test \
--all-features \
--all-targets \
--features libc \
--target i686-unknown-linux-gnu \
--verbose \
--workspace
Expand Down
31 changes: 31 additions & 0 deletions lib/osi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,36 @@
//! particular runtime, but can optionally be combined with the Rust Standard
//! Library.

// MSRV(unknown): This is a wish-list for Rust features that either have no
// clear path to stabilization, or just do not exist. Only features
// relevant to the development of this project are listed.
//
// - rustdoc self-type: Jumping to the documentation of a method in rustdoc
// html renderings does not show the self-type. It is often cumbersome to
// scroll up to the exact place where the `impl` is shown. It would be nice
// if the self-type was shown, or there was another way to quickly jump to
// it via an anchor.
//
// - rustfmt optout: There is no global opt-out for rustfmt. While individual
// items can be annotated with `#[rustfmt::skip]`, the root module of a
// crate cannot be annotated like this (NB: inner attributes like
// `#![rustfmt::skip]` are not stable).
// While projects can decide to not run `rustfmt`, it would be nice to
// annotate the code-base so IDEs will also not format the code
// automatically.
//
// - maybe-owned types: When objects borrow data, the data cannot live in the
// same object, since Rust does not allow self-referential types. A common
// workaround is to make such objects own the data instead, but this is
// sub-optimal and leads to unneeded copies. It would be nice to have some
// official support to represent data that can be either owned or borrowed,
// similar to `core::borrow::Cow`, but without the requirement for `Clone`.
//
// - memchr(), memmem(): While strings have two-way search support in the Rust
// standard library, no such features are exposed for searching u8. Given
// that these can be greatly optimized by the compiler, they seem a worthy
// fit for the standard library.

#![allow(clippy::assertions_on_constants)]
#![allow(clippy::identity_op)]
#![allow(clippy::manual_range_contains)]
Expand Down Expand Up @@ -34,6 +64,7 @@ pub mod json;
pub mod marker;
pub mod mem;
pub mod meta;
pub mod mown;
pub mod never;
pub mod pin;
pub mod ptr;
Expand Down
213 changes: 213 additions & 0 deletions lib/osi/src/mown.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
//! # Maybe-Owned Type
//!
//! This module provides the `Mown` type. This is a generic type that
//! represents data that is either owned or borrowed.

/// A *Maybe-Owned* type represents values that are either owned or borrowed.
///
/// The main motivation of the `Mown` type is to generalize whether an object
/// stores borrowed or owned data. When an object stores a reference to
/// borrowed data, the caller must ensure this data lives long enough. This is
/// often cumbersome since Rust lacks support for self-referential data types.
/// But if the object instead stores a [`Mown`] object, the caller can decide
/// whether to pass in borrowed or owned data.
///
/// ## Similarity to Cow
///
/// This type is almost identical to [`Cow`](alloc::borrow::Cow), but does not
/// require [`Clone`](core::clone::Clone) or any kind of support for
/// mutability.
pub enum Mown<'a, B: ?Sized, O = &'a B> {
Borrowed(&'a B),
Owned(O),
}

impl<'a, B, O> Mown<'a, B, O>
where
B: 'a + ?Sized,
{
/// Create a new borrowed `Mown`.
pub const fn new_borrowed(v: &'a B) -> Self {
Self::Borrowed(v)
}

/// Create a new owned `Mown`.
pub const fn new_owned(v: O) -> Self {
Self::Owned(v)
}

/// Check whether the `Mown` is borrowed.
pub const fn is_borrowed(&self) -> bool {
match *self {
Self::Borrowed(_) => true,
Self::Owned(_) => false,
}
}

/// Check whether the `Mown` is owned.
pub const fn is_owned(&self) -> bool {
!self.is_borrowed()
}
}

impl<'a, B, O> Mown<'a, B, O>
where
B: ?Sized,
O: core::borrow::Borrow<B>,
{
/// Dereference the `Mown` to the borrowed type.
pub fn deref(&self) -> &B {
match *self {
Self::Borrowed(v) => v,
Self::Owned(ref v) => v.borrow(),
}
}
}

impl<'a, B, O, T> core::convert::AsRef<T> for Mown<'a, B, O>
where
B: ?Sized + core::convert::AsRef<T>,
O: core::borrow::Borrow<B>,
T: ?Sized,
{
fn as_ref(&self) -> &T {
self.deref().as_ref()
}
}

impl<'a, B, O> core::clone::Clone for Mown<'a, B, O>
where
B: ?Sized,
O: core::clone::Clone,
{
fn clone(&self) -> Self {
match *self {
Self::Borrowed(v) => Self::Borrowed(v),
Self::Owned(ref v) => Self::Owned(v.clone()),
}
}
}

impl<'a, B, O> core::fmt::Debug for Mown<'a, B, O>
where
B: ?Sized + core::fmt::Debug,
O: core::borrow::Borrow<B>,
{
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
match *self {
Self::Borrowed(v) => fmt.debug_tuple("Mown::Borrowed").field(&v).finish(),
Self::Owned(ref v) => fmt.debug_tuple("Mown::Owned").field(&v.borrow()).finish(),
}
}
}

impl<'a, B, O> core::default::Default for Mown<'a, B, O>
where
B: ?Sized,
O: core::default::Default,
{
fn default() -> Self {
Self::new_owned(O::default())
}
}

impl<'a, B, O> core::ops::Deref for Mown<'a, B, O>
where
B: ?Sized,
O: core::borrow::Borrow<B>,
{
type Target = B;

fn deref(&self) -> &B {
Mown::deref(self)
}
}

impl<'a, B, O> core::cmp::Eq for Mown<'a, B, O>
where
B: ?Sized + core::cmp::Eq,
O: core::borrow::Borrow<B>,
{
}

impl<'a, B, O> core::convert::From<&'a B> for Mown<'a, B, O>
where
B: ?Sized,
{
fn from(v: &'a B) -> Self {
Self::new_borrowed(v)
}
}

impl<'a, B, O> core::hash::Hash for Mown<'a, B, O>
where
B: ?Sized + core::hash::Hash,
O: core::borrow::Borrow<B>,
{
fn hash<Op>(&self, state: &mut Op)
where
Op: core::hash::Hasher,
{
(**self).hash(state)
}
}

impl<'a, B, O> core::cmp::Ord for Mown<'a, B, O>
where
B: ?Sized + core::cmp::Ord,
O: core::borrow::Borrow<B>,
{
fn cmp(&self, v: &Self) -> core::cmp::Ordering {
(**self).cmp(v)
}
}

impl<'a, B, O> core::cmp::PartialEq for Mown<'a, B, O>
where
B: ?Sized + core::cmp::PartialEq,
O: core::borrow::Borrow<B>,
{
fn eq(&self, v: &Self) -> bool {
(**self).eq(v)
}
}

impl<'a, B, O> core::cmp::PartialOrd for Mown<'a, B, O>
where
B: ?Sized + core::cmp::PartialOrd,
O: core::borrow::Borrow<B>,
{
fn partial_cmp(&self, v: &Self) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(v)
}
}

#[cfg(test)]
mod test {
use super::*;
use alloc::string::String;

// Verify basic behavior of `Mown`.
#[test]
fn basic() {
// Verify that niches are used by `Mown`. Since `String` simply wraps
// `Vec`, we know that it has a non-zero-annotation. Thus the `Mown`
// enum must be able to re-use the nieche bits.
assert_eq!(
core::mem::size_of::<Mown<'_, str, String>>(),
core::mem::size_of::<String>(),
);

// Create owned and borrowed variants and compare them.
let b = Mown::<str, String>::new_borrowed("foobar");
let o = Mown::<str, String>::new_owned("foobar".into());
assert_eq!(b, o);
assert_eq!(&*b, &*o);
assert_eq!(&*b, "foobar");
assert_eq!(&*o, "foobar");
assert!(b.is_borrowed());
assert!(!o.is_borrowed());
assert!(!b.is_owned());
assert!(o.is_owned());
}
}
1 change: 1 addition & 0 deletions lib/sys/src/ffi/linux/native/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ osi::cfg::cond! {
},
}

#[allow(unused)]
pub use inner::*;