Skip to content

Commit

Permalink
Make UnsafeFromPrimitive a trait (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
ia0 authored Mar 18, 2023
1 parent c90528c commit 9b4642e
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 20 deletions.
11 changes: 11 additions & 0 deletions num_enum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ pub trait TryFromPrimitive: Sized {
fn try_from_primitive(number: Self::Primitive) -> Result<Self, TryFromPrimitiveError<Self>>;
}

pub trait UnsafeFromPrimitive: Sized {
type Primitive: Copy + Eq;

/// Transmutes into an enum from its primitive.
///
/// # Safety
///
/// - `number` must represent a valid discriminant of `Self`.
unsafe fn from_unchecked(number: Self::Primitive) -> Self;
}

pub struct TryFromPrimitiveError<Enum: TryFromPrimitive> {
pub number: Enum::Primitive,
}
Expand Down
26 changes: 6 additions & 20 deletions num_enum_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use syn::{
parse_macro_input, parse_quote,
spanned::Spanned,
Attribute, Data, DeriveInput, Error, Expr, ExprLit, ExprUnary, Fields, Ident, Lit, LitInt,
LitStr, Meta, Result, UnOp,
Meta, Result, UnOp,
};

macro_rules! die {
Expand Down Expand Up @@ -944,6 +944,7 @@ fn get_crate_name() -> String {
#[proc_macro_derive(UnsafeFromPrimitive, attributes(num_enum))]
pub fn derive_unsafe_from_primitive(stream: TokenStream) -> TokenStream {
let enum_info = parse_macro_input!(stream as EnumInfo);
let krate = Ident::new(&get_crate_name(), Span::call_site());

if enum_info.has_default_variant() {
let span = enum_info
Expand All @@ -968,26 +969,11 @@ pub fn derive_unsafe_from_primitive(stream: TokenStream) -> TokenStream {
ref name, ref repr, ..
} = enum_info;

let doc_string = LitStr::new(
&format!(
r#"
Transmutes `number: {repr}` into a [`{name}`].
# Safety
- `number` must represent a valid discriminant of [`{name}`]
"#,
repr = repr,
name = name,
),
Span::call_site(),
);

TokenStream::from(quote! {
impl #name {
#[doc = #doc_string]
#[inline]
pub unsafe fn from_unchecked(number: #repr) -> Self {
impl ::#krate::UnsafeFromPrimitive for #name {
type Primitive = #repr;

unsafe fn from_unchecked(number: Self::Primitive) -> Self {
::core::mem::transmute(number)
}
}
Expand Down

0 comments on commit 9b4642e

Please sign in to comment.