/*! This example demonstrates various ways to obfuscate the string literals in more complex scenarios. The example presented here uses an enum because it can be challenging to return a string representation of it. */ use std::fmt; use obfstr::{obfstr, obfstring, position}; // Let's try to obfuscate the string representation of this enum. pub enum Example { Foo, Bar, Baz, } impl Example { // Returns an owned String but this allocates memory. pub fn to_str1(&self) -> String { match self { Example::Foo => obfstring!("Foo"), Example::Bar => obfstring!("Bar"), Example::Baz => obfstring!("Baz"), } } // Use a callback to keep the string slice allocated on the stack but this gets annoying in more complex scenarios. pub fn to_str2 R>(&self, mut f: F) -> R { match self { Example::Foo => f(obfstr!("Foo")), Example::Bar => f(obfstr!("Bar")), Example::Baz => f(obfstr!("Baz")) } } // Use a buffer to hold the deobfuscated string. Panics if the buffer is too small. pub fn to_str3<'a>(&self, buf: &'a mut [u8; 4]) -> &'a str { match self { Example::Foo => obfstr!(buf <- "Foo"), Example::Bar => obfstr!(buf <- "Bar"), Example::Baz => obfstr!(buf <- "Baz"), } } // Allocate the string literals via concatenation. pub const POOL: &'static str = concat!("Foo", "Bar", "Baz"); // Deobfuscate the POOL constant and pass it here as the pool argument. // This to string implementation will slice the right substring. pub fn to_str4<'a>(&self, pool: &'a str) -> &'a str { match self { Example::Foo => &pool[position!(Example::POOL, "Foo")], Example::Bar => &pool[position!(Example::POOL, "Bar")], Example::Baz => &pool[position!(Example::POOL, "Baz")], } } } impl fmt::Display for Example { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_str2(|s| f.write_str(s)) } } fn main() {}