use proc_macro2::TokenStream;
#[derive(Debug)]
pub struct ResolvedPlaceholderExpr {
pub expr: TokenStream,
pub pointer_value: bool
}
impl ResolvedPlaceholderExpr {
pub fn new(expr: TokenStream) -> Self {
Self::with(expr, false)
}
pub fn pointer(expr: TokenStream) -> Self {
Self::with(expr, true)
}
pub fn with(expr: TokenStream, pointer_value: bool) -> Self {
Self {
expr,
pointer_value
}
}
pub fn expr_tokens(&self) -> TokenStream {
self.expr.clone()
}
}
pub fn pointer_prefers_value(ty: &syn::Type) -> bool {
match ty {
syn::Type::Ptr(_) => true,
syn::Type::Reference(reference) => reference.mutability.is_none(),
syn::Type::Path(path) => path
.path
.segments
.last()
.map(|segment| segment.ident == "NonNull")
.unwrap_or(false),
_ => false
}
}
#[cfg(test)]
mod tests {
use quote::quote;
use super::*;
#[test]
fn test_resolved_placeholder_expr_new() {
let expr = quote!(value);
let resolved = ResolvedPlaceholderExpr::new(expr.clone());
assert_eq!(resolved.expr.to_string(), expr.to_string());
assert!(!resolved.pointer_value);
}
#[test]
fn test_resolved_placeholder_expr_pointer() {
let expr = quote!(value);
let resolved = ResolvedPlaceholderExpr::pointer(expr.clone());
assert_eq!(resolved.expr.to_string(), expr.to_string());
assert!(resolved.pointer_value);
}
#[test]
fn test_resolved_placeholder_expr_with_false() {
let expr = quote!(value);
let resolved = ResolvedPlaceholderExpr::with(expr.clone(), false);
assert_eq!(resolved.expr.to_string(), expr.to_string());
assert!(!resolved.pointer_value);
}
#[test]
fn test_resolved_placeholder_expr_with_true() {
let expr = quote!(value);
let resolved = ResolvedPlaceholderExpr::with(expr.clone(), true);
assert_eq!(resolved.expr.to_string(), expr.to_string());
assert!(resolved.pointer_value);
}
#[test]
fn test_resolved_placeholder_expr_tokens() {
let expr = quote!(some_value);
let resolved = ResolvedPlaceholderExpr::new(expr.clone());
let tokens = resolved.expr_tokens();
assert_eq!(tokens.to_string(), expr.to_string());
}
#[test]
fn test_pointer_prefers_value_for_raw_pointer() {
let ty: syn::Type = syn::parse_quote!(*const i32);
assert!(pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_mutable_raw_pointer() {
let ty: syn::Type = syn::parse_quote!(*mut i32);
assert!(pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_immutable_reference() {
let ty: syn::Type = syn::parse_quote!(&i32);
assert!(pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_mutable_reference() {
let ty: syn::Type = syn::parse_quote!(&mut i32);
assert!(!pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_non_null() {
let ty: syn::Type = syn::parse_quote!(NonNull<i32>);
assert!(pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_non_null_qualified() {
let ty: syn::Type = syn::parse_quote!(std::ptr::NonNull<i32>);
assert!(pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_regular_type() {
let ty: syn::Type = syn::parse_quote!(String);
assert!(!pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_generic_type() {
let ty: syn::Type = syn::parse_quote!(Vec<i32>);
assert!(!pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_tuple() {
let ty: syn::Type = syn::parse_quote!((i32, String));
assert!(!pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_array() {
let ty: syn::Type = syn::parse_quote!([i32; 10]);
assert!(!pointer_prefers_value(&ty));
}
#[test]
fn test_pointer_prefers_value_for_slice() {
let ty: syn::Type = syn::parse_quote!([i32]);
assert!(!pointer_prefers_value(&ty));
}
}