If the main requirement is not making the inner raw field visible to my_function and you're okay with consuming the original MyStrWrapper instance before wrapping the inner &str in a new instance then I would suggest using the From trait to convert between MyStrWrapper and &str and use that within your implementation of my_function. Example:
struct MyStrWrapper<'a> {
raw: &'a str,
}
impl<'a> From<MyStrWrapper<'a>> for &'a str {
fn from(item: MyStrWrapper<'a>) -> Self {
item.raw
}
}
fn my_function<'inp>(s: MyStrWrapper<'inp>) -> MyStrWrapper<'inp> {
// convert MyStrWrapper into &str without exposing "raw" field to function
let inner_str = s.into();
// do whatever you need to do with inner_str here
// re-wrap inner_str here
MyStrWrapper {
raw: inner_str,
}
}
fn main() {
let s = MyStrWrapper {
raw: "Hello, world!",
};
my_function(s);
}
playground
If you really want to hide raw from my_function you can also implement the conversion in the other direction, &str to MyStrWrapper using the TryFrom trait since it's possible for the conversion to fail if the invariant isn't met. Updated example:
use std::convert::TryInto;
use std::convert::TryFrom;
struct MyStrWrapper<'a> {
raw: &'a str,
}
impl<'a> From<MyStrWrapper<'a>> for &'a str {
fn from(item: MyStrWrapper<'a>) -> Self {
item.raw
}
}
#[derive(Debug)]
enum MyInvariant {
FailureReason
}
impl<'a> TryFrom<&'a str> for MyStrWrapper<'a> {
type Error = MyInvariant;
fn try_from(item: &'a str) -> Result<Self, Self::Error> {
// check invariant on item
// if fails return Err(MyInvariant::FailureReason)
// else
Ok(MyStrWrapper {
raw: item
})
}
}
fn my_function<'inp>(s: MyStrWrapper<'inp>) -> MyStrWrapper<'inp> {
// convert MyStrWrapper into &str without exposing "raw" field to function
let inner_str: &str = s.into();
// do whatever you need to do with inner_str here
// re-wrap inner_str here
inner_str.try_into().unwrap()
}
fn main() {
let s = MyStrWrapper {
raw: "Hello, world!",
};
my_function(s);
}
playground