Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no_std support #7

Merged
merged 10 commits into from
Mar 11, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
profile: minimal
toolchain: nightly
override: true
- name: Test with no feature
- name: Test with default features
uses: actions-rs/cargo@v1
with:
command: test
Expand All @@ -28,7 +28,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: doc
args: --no-deps --features ipv_future,rfc6874bis
args: --no-deps --features ipv_future,rfc6874bis,std
- name: Deploy docs
uses: peaceiris/actions-gh-pages@v3
with:
Expand Down
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ categories = ["encoding", "parser-implementations"]
bitflags = "1.3.2"

[features]
default = ["std"]
ipv_future = []
rfc6874bis = []
unstable = []
std = []

[package.metadata.docs.rs]
features = ["ipv_future", "rfc6874bis"]
features = ["ipv_future", "rfc6874bis", "std"]

# Commented out to reduce compile time.

Expand Down
8 changes: 6 additions & 2 deletions src/enc/estring.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::{borrow::Borrow, fmt, hash, marker::PhantomData, ops::Deref};
use alloc::string::String;
use core::{borrow::Borrow, fmt, hash, marker::PhantomData, ops::Deref};

#[cfg(feature = "unstable")]
use alloc::vec::Vec;

use super::{
encoder::Encoder,
Expand Down Expand Up @@ -341,7 +345,7 @@ impl<E: Encoder> Clone for EString<E> {
impl<E: Encoder> fmt::Debug for EString<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EString")
.field("encoder", &std::any::type_name::<E>())
.field("encoder", &core::any::type_name::<E>())
.field("contents", &self.string)
.finish()
}
Expand Down
8 changes: 5 additions & 3 deletions src/enc/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use super::table;
#[cfg(feature = "unstable")]
use super::table::Table;

use std::{fmt, ptr};
use alloc::vec::Vec;
use core::{fmt, ptr};

#[cfg(feature = "unstable")]
use std::{borrow::Cow, str};
use alloc::{borrow::Cow, str, string::String};

/// Returns immediately with an encoding error.
macro_rules! err {
Expand Down Expand Up @@ -57,6 +58,7 @@ impl EncodingError {
}
}

#[cfg(feature = "std")]
impl std::error::Error for EncodingError {}

impl fmt::Display for EncodingError {
Expand All @@ -70,7 +72,7 @@ impl fmt::Display for EncodingError {
}
}

pub(crate) type Result<T, E = EncodingError> = std::result::Result<T, E>;
pub(crate) type Result<T, E = EncodingError> = core::result::Result<T, E>;

#[cfg(feature = "unstable")]
const fn gen_hex_table() -> [u8; 512] {
Expand Down
14 changes: 9 additions & 5 deletions src/enc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,16 @@ pub fn validate<S: AsRef<[u8]> + ?Sized>(s: &S, table: &Table) -> Result<()> {
}
}

use std::{
use alloc::{
borrow::{self, Cow},
string::{FromUtf8Error, String},
vec::Vec,
};
use core::{
fmt, hash,
iter::FusedIterator,
mem,
str::{self, Utf8Error},
string::FromUtf8Error,
};

use crate::view::View;
Expand Down Expand Up @@ -275,7 +278,7 @@ impl EStr {
/// assert_eq!(dec.to_str()?, "233");
/// assert!(dec.decoded_any());
/// assert_eq!(buf, b"233");
/// # Ok::<_, std::str::Utf8Error>(())
/// # Ok::<_, core::str::Utf8Error>(())
/// ```
#[cfg(feature = "unstable")]
#[inline]
Expand Down Expand Up @@ -778,7 +781,7 @@ impl FusedIterator for SplitView<'_> {}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BufferTooSmallError(());

#[cfg(feature = "unstable")]
#[cfg(all(feature = "unstable", feature = "std"))]
impl std::error::Error for BufferTooSmallError {}

#[cfg(feature = "unstable")]
Expand All @@ -791,7 +794,8 @@ impl fmt::Display for BufferTooSmallError {
#[cfg(feature = "unstable")]
pub(crate) mod internal {
use crate::enc::BufferTooSmallError;
use std::{collections::TryReserveError, mem::MaybeUninit};
use alloc::{collections::TryReserveError, string::String, vec::Vec};
use core::mem::MaybeUninit;

pub trait AsMutVec {
unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8>;
Expand Down
3 changes: 2 additions & 1 deletion src/fmt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use std::fmt;
use alloc::string::String;
use core::fmt;

impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
10 changes: 8 additions & 2 deletions src/internal.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#![allow(missing_debug_implementations)]

use std::{
use alloc::{string::String, vec::Vec};
use core::{
cell::Cell,
mem::MaybeUninit,
num::NonZeroU32,
ops::{Deref, DerefMut},
};

#[cfg(feature = "std")]
use std::net::{Ipv4Addr, Ipv6Addr};

use super::*;
use bitflags::bitflags;

Expand Down Expand Up @@ -231,15 +235,17 @@ pub struct AuthData {

#[derive(Clone, Copy)]
pub union RawHostData {
#[cfg(feature = "std")]
pub ipv4_addr: Ipv4Addr,
pub ipv6: Ipv6Data,
#[cfg(feature = "ipv_future")]
pub ipv_future_dot_i: u32,
pub reg_name: (),
pub none: (),
}

#[derive(Clone, Copy)]
pub struct Ipv6Data {
#[cfg(feature = "std")]
pub addr: Ipv6Addr,
#[cfg(feature = "rfc6874bis")]
pub zone_id_start: Option<NonZeroU32>,
Expand Down
49 changes: 31 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)]
#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(feature = "std"), no_std)]

//! A generic URI parser that strictly adheres to IETF [RFC 3986].
//!
Expand All @@ -9,11 +10,14 @@
//!
//! # Feature flags
//!
//! All features are disabled by default. However, note that these features each
//! alter the enum [`HostData`] in a backward incompatible way that could make it
//! All features except `std` are disabled by default. Note that the last two features
//! each alter the enum [`HostData`] in a backward incompatible way that could make it
//! impossible for two crates that depend on different features of `fluent-uri` to
//! be used together.
//!
//! - `std`: Enables `std` support. This includes [`Error`] implementations
//! and `Ip{v4, v6}Addr` support in [`HostData`].
//!
//! - `ipv_future`: Enables the parsing of [IPvFuture] literal addresses,
//! which fails with [`InvalidIpLiteral`] when disabled.
//!
Expand All @@ -26,9 +30,12 @@
//!
//! This feature is based on the homonymous [draft] and is thus subject to change.
//!
//! [`Error`]: std::error::Error
//! [IPvFuture]: https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2
//! [`InvalidIpLiteral`]: ParseErrorKind::InvalidIpLiteral
//! [draft]: https://datatracker.ietf.org/doc/html/draft-ietf-6man-rfc6874bis-02
//! [draft]: https://datatracker.ietf.org/doc/html/draft-ietf-6man-rfc6874bis-05

extern crate alloc;

/// Utilities for percent-encoding.
pub mod enc;
Expand All @@ -41,13 +48,11 @@ pub use view::*;
mod parser;

use crate::enc::{EStr, Split};
use std::{
marker::PhantomData,
mem::ManuallyDrop,
net::{Ipv4Addr, Ipv6Addr},
ptr::NonNull,
slice, str,
};
use alloc::{string::String, vec::Vec};
use core::{iter::Iterator, marker::PhantomData, mem::ManuallyDrop, ptr::NonNull, slice, str};

#[cfg(feature = "std")]
use std::net::{Ipv4Addr, Ipv6Addr};

mod internal;
use internal::*;
Expand Down Expand Up @@ -90,9 +95,10 @@ impl ParseError {
}
}

#[cfg(feature = "std")]
impl std::error::Error for ParseError {}

type Result<T, E = ParseError> = std::result::Result<T, E>;
type Result<T, E = ParseError> = core::result::Result<T, E>;

#[cold]
fn len_overflow() -> ! {
Expand Down Expand Up @@ -135,7 +141,7 @@ fn len_overflow() -> ! {
/// # Examples
///
/// Create and convert between `Uri<&str>` and `Uri<String>`:
///
///
/// ```
/// use fluent_uri::Uri;
///
Expand Down Expand Up @@ -882,19 +888,22 @@ impl<'i, 'o, T: Io<'i, 'o>> Host<T> {
/// Returns the structured host data.
#[inline]
pub fn data(&'i self) -> HostData<'o> {
let data = self.raw_data();
let _data = self.raw_data();
let tag = self.auth.uri.tag;
// SAFETY: We only access the union after checking the tag.
unsafe {
if tag.contains(Tag::HOST_REG_NAME) {
// SAFETY: The validation is done.
return HostData::RegName(EStr::new_unchecked(self.as_str().as_bytes()));
} else if tag.contains(Tag::HOST_IPV4) {
return HostData::Ipv4(data.ipv4_addr);
return HostData::Ipv4(
#[cfg(feature = "std")]
_data.ipv4_addr,
);
}
#[cfg(feature = "ipv_future")]
if !tag.contains(Tag::HOST_IPV6) {
let dot_i = data.ipv_future_dot_i;
let dot_i = _data.ipv_future_dot_i;
let bounds = self.bounds();
// SAFETY: The indexes are within bounds and the validation is done.
return HostData::IpvFuture {
Expand All @@ -903,10 +912,11 @@ impl<'i, 'o, T: Io<'i, 'o>> Host<T> {
};
}
HostData::Ipv6 {
addr: data.ipv6.addr,
#[cfg(feature = "std")]
addr: _data.ipv6.addr,
// SAFETY: The indexes are within bounds and the validation is done.
#[cfg(feature = "rfc6874bis")]
zone_id: data
zone_id: _data
.ipv6
.zone_id_start
.map(|start| self.auth.uri.slice(start.get(), self.bounds().1 - 1)),
Expand All @@ -919,10 +929,13 @@ impl<'i, 'o, T: Io<'i, 'o>> Host<T> {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HostData<'a> {
/// An IPv4 address.
Ipv4(Ipv4Addr),
#[cfg_attr(not(feature = "std"), non_exhaustive)]
Ipv4(#[cfg(feature = "std")] Ipv4Addr),
/// An IPv6 address.
#[cfg_attr(not(feature = "std"), non_exhaustive)]
Ipv6 {
/// The address.
#[cfg(feature = "std")]
addr: Ipv6Addr,
/// An optional zone identifier.
///
Expand Down