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

error[E0492]: statics cannot refer to interior mutable data #283

Open
abc-mikey opened this issue Mar 26, 2023 · 2 comments
Open

error[E0492]: statics cannot refer to interior mutable data #283

abc-mikey opened this issue Mar 26, 2023 · 2 comments
Labels

Comments

@abc-mikey
Copy link

abc-mikey commented Mar 26, 2023

This is probably me not understanding something rather than a bug but why do the following static declarations work but using the same declaration as part of phf_map! does not?

static X: Mutex<String> = Mutex::new(String::new());
static XS: phf::Map<&'static str, Mutex<String>> = phf_map! {
        "foo" => Mutex::new(String::new()),
        "bar" => Mutex::new(String::new())
};

static Y: Lazy<String> = Lazy::new(|| "bazz".to_string());
static YS: phf::Map<&'static str, Lazy<String>> = phf_map! {
        "fee" => Lazy::new(|| "bizz".to_string()),
        "fi"  => Lazy::new(|| "buzz".to_string())
};
@abc-mikey
Copy link
Author

I found the following syntax seems to work, but the syntax is nasty:

static YS: phf::Map<&'static str, &Lazy<String>> = phf_map! {
        "fee" => { static _DUMMY: Lazy<String> = Lazy::new(|| "bizz".to_string()); &_DUMMY },
        "fi"  => { static _DUMMY: Lazy<String> = Lazy::new(|| "buzz".to_string()); &_DUMMY },
};

@JohnTitor
Copy link
Member

proc-macro doesn't handle it nicely, I think. We've declared:

fn from_expr(expr: &Expr) -> Option<ParsedKey> {
match expr {
Expr::Lit(lit) => match &lit.lit {
Lit::Str(s) => Some(ParsedKey::Str(s.value())),
Lit::ByteStr(s) => Some(ParsedKey::Binary(s.value())),
Lit::Byte(s) => Some(ParsedKey::U8(s.value())),
Lit::Char(s) => Some(ParsedKey::Char(s.value())),
Lit::Int(s) => match s.suffix() {
// we've lost the sign at this point, so `-128i8` looks like `128i8`,
// which doesn't fit in an `i8`; parse it as a `u8` and cast (to `0i8`),
// which is handled below, by `Unary`
"i8" => Some(ParsedKey::I8(s.base10_parse::<u8>().unwrap() as i8)),
"i16" => Some(ParsedKey::I16(s.base10_parse::<u16>().unwrap() as i16)),
"i32" => Some(ParsedKey::I32(s.base10_parse::<u32>().unwrap() as i32)),
"i64" => Some(ParsedKey::I64(s.base10_parse::<u64>().unwrap() as i64)),
"i128" => Some(ParsedKey::I128(s.base10_parse::<u128>().unwrap() as i128)),
"u8" => Some(ParsedKey::U8(s.base10_parse::<u8>().unwrap())),
"u16" => Some(ParsedKey::U16(s.base10_parse::<u16>().unwrap())),
"u32" => Some(ParsedKey::U32(s.base10_parse::<u32>().unwrap())),
"u64" => Some(ParsedKey::U64(s.base10_parse::<u64>().unwrap())),
"u128" => Some(ParsedKey::U128(s.base10_parse::<u128>().unwrap())),
_ => None,
},
Lit::Bool(s) => Some(ParsedKey::Bool(s.value)),
_ => None,
},
Expr::Array(array) => {
let mut buf = vec![];
for expr in &array.elems {
match expr {
Expr::Lit(lit) => match &lit.lit {
Lit::Int(s) => match s.suffix() {
"u8" | "" => buf.push(s.base10_parse::<u8>().unwrap()),
_ => return None,
},
_ => return None,
},
_ => return None,
}
}
Some(ParsedKey::Binary(buf))
}
Expr::Unary(unary) => {
// if we received an integer literal (always unsigned) greater than i__::max_value()
// then casting it to a signed integer type of the same width will negate it to
// the same absolute value so we don't need to negate it here
macro_rules! try_negate (
($val:expr) => {if $val < 0 { $val } else { -$val }}
);
match unary.op {
UnOp::Neg(_) => match ParsedKey::from_expr(&unary.expr)? {
ParsedKey::I8(v) => Some(ParsedKey::I8(try_negate!(v))),
ParsedKey::I16(v) => Some(ParsedKey::I16(try_negate!(v))),
ParsedKey::I32(v) => Some(ParsedKey::I32(try_negate!(v))),
ParsedKey::I64(v) => Some(ParsedKey::I64(try_negate!(v))),
ParsedKey::I128(v) => Some(ParsedKey::I128(try_negate!(v))),
_ => None,
},
UnOp::Deref(_) => {
let mut expr = &*unary.expr;
while let Expr::Group(group) = expr {
expr = &*group.expr;
}
match expr {
Expr::Lit(ExprLit {
lit: Lit::ByteStr(s),
..
}) => Some(ParsedKey::Binary(s.value())),
_ => None,
}
}
_ => None,
}
}
Expr::Group(group) => ParsedKey::from_expr(&group.expr),
#[cfg(feature = "unicase")]
Expr::Call(call) => {
if let Expr::Path(ep) = call.func.as_ref() {
let segments = &mut ep.path.segments.iter().rev();
let last = &segments.next()?.ident;
let last_ahead = &segments.next()?.ident;
let is_unicode = last_ahead == "UniCase" && last == "unicode";
let is_ascii = last_ahead == "UniCase" && last == "ascii";
if call.args.len() == 1 && (is_unicode || is_ascii) {
if let Some(Expr::Lit(ExprLit {
attrs: _,
lit: Lit::Str(s),
})) = call.args.first()
{
let v = if is_unicode {
UniCase::unicode(s.value())
} else {
UniCase::ascii(s.value())
};
Some(ParsedKey::UniCase(v))
} else {
None
}
} else {
None
}
} else {
None
}
}
_ => None,
}
}

@JohnTitor JohnTitor added C-enhancement A-macros Area: phf-macros labels Apr 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants