Rust Enums, Match & Destructuring - help me understand - rust

I'm learning Rust. I have some programming experience in JavaScript and Python and had a good go at Haskell once.
I'm learning Enums but finding it hard to use them. Here's what I'm doing:
fn main(){
enum IpAddr {
V4(u8, u8, u8, u8),
V6(u16, u16, u16, u16, u16, u16, u16, u16),
}
impl IpAddr {
fn last_octet (&self) -> &u16 {
match &self {
IpAddr::V4(_, _, _, d) => d as &u16,
IpAddr::V6(_, _, _, _, _, _, _, h) => h,
}
}
}
let localhost4 = IpAddr::V4(127, 0, 0, 1);
let localhost6 = IpAddr::V6(0, 0, 0, 0, 0, 0, 0, 1);
println!("{}", localhost4.last_octet());
println!("{}", localhost6.last_octet());
}
So, I want to use u8 and u16 respectively for IPv4 and IPv6 to take advantage of the type system.
I realise my last_octet method can only return one type which is a bit of a limitation, so the obvious approach seems to convert my IPv4 octet to a u16 but I'm unable to find a way to do that.
Any suggestions or improvements on what I've done??
I tried my main function above and it fails on the conversion from u8 to u16.
If I try the same a simple
let u8: u8 = 7;
let u16: u16 = u8 as u16;
there is no problem. So, I'm not understanding something about Enums or methods on them.

The problem is that you're trying to return a reference to a u16 and you can't trivially cast between references to different types. The good news is that there's almost never a good reason to return a reference to an integer instead of just an integer. All the integral types in Rust are Copy, i.e. they don't get moved around, they're just copied bit by bit because it's much cheaper and they don't own any data that could get aliased in the process. So you can just return a u16 instead of a &u16 and upcast your u8:
impl IpAddr {
fn last_octet (&self) -> u16 {
match &self {
// note the dereferencing operator `*` here to turn a `&u8` into a `u8`
// before casting it to a `u16`:
IpAddr::V4(_, _, _, d) => *d as u16,
// here we just need to dereference:
IpAddr::V6(_, _, _, _, _, _, _, h) => *h,
}
}
}

Related

can you carry mutable state in nom?

I've been playing around with nom and I'm wondering how to track state when you are parsing something. For practice I'm using nom to write a QOI image file library.
So far I've tried using closures and wrapping the parsers in a struct implementation. I'm fairly sure I could get it done with global mutable state, but we all know that's a sin. I've posted a minimal(ish) example below with the error I get on my struct impl version:
use nom::{
branch::alt,
bytes::streaming::tag,
error::Error,
error::ErrorKind,
error::ParseError,
multi::{count, many1},
number::complete::be_u8,
sequence::{pair, terminated, tuple},
IResult,
};
type Pixel = [u8; 3];
fn px_hash(px: Pixel) -> usize {
(px[0] * 3 + px[1] * 5 + px[2] * 7) as usize & 64
}
pub struct Decoder {
table: [Pixel; 64],
prev: Pixel,
}
const QOI_END_TAG: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 1];
const QOI_FAKE_HEADER: u8 = 0xff;
const QOI_OP_RGB: u8 = 0xfe;
impl Decoder {
pub fn decode(&mut self, input: &[u8]) -> IResult<&[u8], Vec<Pixel>> {
pair(
tag(&[QOI_FAKE_HEADER]),
terminated(many1(alt((self.rgb, self.index))), tag(QOI_END_TAG)),
)(input)
.map(|(_, (next_input, pixels))| (next_input, pixels))
}
pub fn rgb(&mut self, input: &[u8]) -> IResult<&[u8], Pixel> {
tuple((tag(&[QOI_OP_RGB]), count(be_u8, 3)))(input).map(|(next_input, (_, c))| {
let px = [c[0], c[1], c[2]];
self.prev = px;
self.table[px_hash(px)] = px;
(next_input, px)
})
}
pub fn index(&mut self, input: &[u8]) -> IResult<&[u8], Pixel> {
be_u8(input).and_then(|(next_input, res)| {
if res >= 64 {
let e: ErrorKind = ErrorKind::Tag;
nom::Err::Error(Error::from_error_kind(input, ErrorKind::Tag));
}
let res = res as usize;
self.prev = self.table[res];
Ok((next_input, self.table[res]))
})
}
}
And here's the error I get.
error[E0615]: attempted to take value of method `rgb` on type `&mut min::Decoder`
--> src/min.rs:32:40
|
32 | terminated(many1(alt((self.rgb, self.index))), tag(QOI_END_TAG)),
| ^^^ method, not a field
I understand the the signature isn't really what's expected, as self is an implicit argument, but closures have that problem except even worse.
Does anyone know a work around for a problem like this? Carrying state is a common requirement for any kind of decompression etc. so I'm sure that this issue has come up for people but my google-fu hasn't come up with much.
I suppose it's also possible that I'm using the wrong tool for this job, but I was under the impression that parser combinators could get something like this done.

Initialize a Vec with not-None values only

If I have variables like this:
let a: u32 = ...;
let b: Option<u32> = ...;
let c: u32 = ...;
, what is the shortest way to make a vector of those values, so that b is only included if it's Some?
In other words, is there something simpler than this:
let v = match b {
None => vec![a, c],
Some(x) => vec![a, x, c],
};
P.S. I would prefer a solution where we don't need to use the variables more than once. Consider this example:
let some_person: String = ...;
let best_man: Option<String> = ...;
let a_third_person: &str = ...;
let another_opt: Option<String> = ...;
...
As can be seen, we might have to use longer variable names, more than one Option (None), expressions (like a_third_person.to_string()), etc.
Yours is fine, but here's a sophisticated one:
[Some(a), b, Some(c)].into_iter().flatten().collect::<Vec<_>>()
This works since Option impls IntoIterator.
If it depends on just one variable:
b.map(|b| vec![a, b, c]).unwrap_or_else(|| vec![a, c]);
Playground
After some thinking and investigating, I've come with the following crazy thing.
The end goal is to have a macro, optional_vec![], that you can pass it either T or Option<T> and it should behave like described in the question. However, I decided on a strong restriction: it should have the best performance possible. So, you write:
optional_vec![a, b, c]
And get at least the performance of hand-written match, if not more. This forbids the use of the simple [Some(a), b, Some(c)].into_iter().flatten().collect::<Vec<_>>(), suggested in my other answer (though even this solution needs some way to differentiate between Option<T> and just T, which, like we'll see, is not an easy problem at all).
I will first warn that I've not found a way to make my macro work with Option. That is, if you want to build a vector of Option<T> from Option<T> and Option<Option<T>>, it will not work.
When a design a complex macro, I like to think first how the expanded code will look like. And in this macro, we have several hard problems to solve.
First, the macro take plain expressions. But somehow, it needs to switch on their type being T or Option<T>. How should such thing be done?
The feature we use to do such things is specialization.
#![feature(specialization)]
pub trait Optional {
fn some_method(self);
}
impl<T> Optional for T {
default fn some_method(self) {
// Just T
}
}
impl<T> Optional for Option<T> {
fn some_method(self) {
// Option<T>
}
}
Like you probably noticed, now we have two problems: first, specialization is unstable, and I'd like to stay with stable. Second, what should be inside the trait? The second problem is easier to solve, so let's begin with it.
Turns out that the most performant way to do the pushing to the vector is to pre-allocate capacity (Vec::with_capacity), write to the vector by using pointers (don't push(), it optimizes badly!) then set the length (Vec::set_len()).
We can get a pointer to the internal buffer of the vector using Vec::as_mut_ptr(), and advance the pointer via <*mut T>::add(1).
So, we need two methods: one to hint us about the capacity (can be zero for None or one for Some() and non-Option elements), and a write_and_advance() method:
pub trait Optional {
type Item;
fn len(&self) -> usize;
unsafe fn write_and_advance(self, place: &mut *mut Self::Item);
}
impl<T> Optional for T {
default type Item = Self;
default fn len(&self) -> usize { 1 }
default unsafe fn write_and_advance(self, place: &mut *mut Self) {
place.write(self);
*place = place.add(1);
}
}
impl<T> Optional<T> for Option<T> {
type Item = T;
fn len(&self) -> usize { self.is_some() as usize }
unsafe fn write_and_advance(self, place: &mut *mut T) {
if let Some(value) = self {
place.write(value);
*place = place.add(1);
}
}
}
It doesn't even compile! For the why, see Mismatch between associated type and type parameter only when impl is marked `default`. Luckily for us, the trick we'll use to workaround specialization not being stable does work in this situation. But for now, let's assume it works. How will the code using this trait look like?
match (a, b, c) { // The match is here because it's the best binding for liftimes: see https://stackoverflow.com/a/54855986/7884305
(a, b, c) => {
let len = Optional::len(&a) + Optional::len(&b) + Optional::len(&c);
let mut result = ::std::vec::Vec::with_capacity(len);
let mut next_element = result.as_mut_ptr();
unsafe {
Optional::write_and_advance(a, &mut next_element);
Optional::write_and_advance(b, &mut next_element);
Optional::write_and_advance(c, &mut next_element);
result.set_len(len);
}
result
}
}
And it works! Except that it does not, because the specialization does not compile as I said, and we also want to not repeat all of this boilerplate but insert it into a macro.
So, how do we solve the problems with specialization: being unstable and not working?
dtonlay has a very cool trick he calls autoref specialization (BTW, all of this repo is a very recommended reading!). This is a trick that can be used to emulate specialization. It works only in macros, but we're in a macro so this is fine.
I will not elaborate about the trick here (I recommend to read his post; he also used this trick in the excellent and very widely used anyhow crate). In short, the idea is to trick the typechecker by implementing a trait for T under certain conditions (the specialized impl) and other trait for &T for the general case (this could be inherent impl if not coherence). Since Rust performs automatic referencing during method resolution, that is take reference to the receiver as needed, this will work - the typechecker will autoref if needed, and will stop in the first applicable impl - i.e. the specialized impl if it matches, or the general impl otherwise.
Here's an example:
use std::fmt;
pub trait Display {
fn foo(&self);
}
// Level 1
impl<T: fmt::Display> Display for T {
fn foo(&self) { println!("Display({}), {}", std::any::type_name::<T>(), self); }
}
pub trait Debug {
fn foo(&self);
}
// Level 2
impl<T: fmt::Debug> Debug for &T {
fn foo(&self) { println!("Debug({}), {:?}", std::any::type_name::<T>(), self); }
}
macro_rules! foo {
($e:expr) => ((&$e).foo());
}
Playground.
We can use this trick in our case:
#[doc(hidden)]
pub mod autoref_specialization {
#[derive(Copy, Clone)]
pub struct OptionTag;
pub trait OptionKind {
fn optional_kind(&self) -> OptionTag;
}
impl<T> OptionKind for Option<T> {
#[inline(always)]
fn optional_kind(&self) -> OptionTag { OptionTag }
}
impl OptionTag {
#[inline(always)]
pub fn len<T>(self, this: &Option<T>) -> usize { this.is_some() as usize }
#[inline(always)]
pub unsafe fn write_and_advance<T>(self, this: Option<T>, place: &mut *mut T) {
if let Some(value) = this {
place.write(value);
*place = place.add(1);
}
}
}
#[derive(Copy, Clone)]
pub struct DefaultTag;
pub trait DefaultKind {
fn optional_kind(&self) -> DefaultTag;
}
impl<T> DefaultKind for &'_ T {
#[inline(always)]
fn optional_kind(&self) -> DefaultTag { DefaultTag }
}
impl DefaultTag {
#[inline(always)]
pub fn len<T>(self, _this: &T) -> usize { 1 }
#[inline(always)]
pub unsafe fn write_and_advance<T>(self, this: T, place: &mut *mut T) {
place.write(this);
*place = place.add(1);
}
}
}
And the expanded code will look like:
use autoref_specialization::{DefaultKind as _, OptionKind as _};
match (a, b, c) {
(a, b, c) => {
let (a_tag, b_tag, c_tag) = (
(&a).optional_kind(),
(&b).optional_kind(),
(&c).optional_kind(),
);
let len = a_tag.len(&a) + b_tag.len(&b) + c_tag.len(&c);
let mut result = ::std::vec::Vec::with_capacity(len);
let mut next_element = result.as_mut_ptr();
unsafe {
a_tag.write_and_advance(a, &mut next_element);
b_tag.write_and_advance(b, &mut next_element);
c_tag.write_and_advance(c, &mut next_element);
result.set_len(len);
}
result
}
}
It may be tempting to try to convert this immediately into a macro, but we still have one unsolved problem: our macro need to generate identifiers. This may not be obvious, but what if we pass optional_vec![1, Some(2), 3]? We need to generate the bindings for the match (in our case, (a, b, c) => ...) and the tag names ((a_tag, b_tag, c_tag)).
Unfortunately, generating names is not something macro_rules! can do in today's Rust. Fortunately, there is an excellent crate paste (another one from dtonlay!) that is a small proc-macro that allows you to do that. It is even available on the playground!
However, we need a series of identifiers. That can be done with tt-munching, by repeatedly adding some letter (I used a), so you get a, aa, aaa, ... you get the idea.
#[doc(hidden)]
pub mod reexports {
pub use std::vec::Vec;
pub use paste::paste;
}
#[macro_export]
macro_rules! optional_vec {
// Empty case
{ #generate_idents
exprs = []
processed_exprs = [$($e:expr,)*]
match_bindings = [$($binding:ident)*]
tags = [$($tag:ident)*]
} => {{
use $crate::autoref_specialization::{DefaultKind as _, OptionKind as _};
match ($($e,)*) {
($($binding,)*) => {
let ($($tag,)*) = (
$((&$binding).optional_kind(),)*
);
let len = 0 $(+ $tag.len(&$binding))*;
let mut result = $crate::reexports::Vec::with_capacity(len);
let mut next_element = result.as_mut_ptr();
unsafe {
$($tag.write_and_advance($binding, &mut next_element);)*
result.set_len(len);
}
result
}
}
}};
{ #generate_idents
exprs = [$e:expr, $($rest:expr,)*]
processed_exprs = [$($processed_exprs:tt)*]
match_bindings = [$first_binding:ident $($bindings:ident)*]
tags = [$($tags:ident)*]
} => {
$crate::reexports::paste! {
$crate::optional_vec! { #generate_idents
exprs = [$($rest,)*]
processed_exprs = [$($processed_exprs)* $e,]
match_bindings = [
[< $first_binding a >]
$first_binding
$($bindings)*
]
tags = [
[< $first_binding a_tag >]
$($tags)*
]
}
}
};
// Entry
[$e:expr $(, $exprs:expr)* $(,)?] => {
$crate::optional_vec! { #generate_idents
exprs = [$($exprs,)+]
processed_exprs = [$e,]
match_bindings = [__optional_vec_a]
tags = [__optional_vec_a_tag]
}
};
}
Playground.
I can also personally recommend
let mut v = vec![a, c];
v.extend(b);
Short and clear.
Sometime the straight forward solution is the best:
fn jim_power(a: u32, b: Option<u32>, c: u32) -> Vec<u32> {
let mut acc = Vec::with_capacity(3);
acc.push(a);
if let Some(b) = b {
acc.push(b);
}
acc.push(c);
acc
}
fn ys_iii(
some_person: String,
best_man: Option<String>,
a_third_person: String,
another_opt: Option<String>,
) -> Vec<String> {
let mut acc = Vec::with_capacity(4);
acc.push(some_person);
best_man.map(|x| acc.push(x));
acc.push(a_third_person);
another_opt.map(|x| acc.push(x));
acc
}
If you don't care about the order of the values, another option is
Iterator::chain(
[a, c].into_iter(),
[b].into_iter().flatten()
).collect()
Playground

What is the correct way to fill a C string pointer from Rust?

I have a FFI signature I need to implement:
pub unsafe extern fn f(header_size: u32, header_ptr: *mut u8) -> i32;
A FFI caller is expected to provide a buffer header_ptr and the size of that buffer header_size. Rust is expected to fill a string into that buffer up to header_size, and return 0 if successful. The FFI caller is expected to interpret the string as ASCII.
How can I fill that buffer the most idiomatic way, given I have a headers: &str with the content I want to provide?
Right now I have:
let header_bytes = slice::from_raw_parts_mut(header_ptr, header_size as usize);
if header_bytes.len() < headers.len() { return Errors::IndexOutOfBounds as i32; }
for (i, byte) in headers.as_bytes().iter().enumerate() {
header_bytes[i] = *byte;
}
But that feels wrong.
Edit, I think this is not an exact duplicate to this because my question relates to strings, and IIRC there were special considerations when converting &str to CStrings.
Since C strings are not much more than 0-terminated byte arrays converting from Rust strings is very straight forward. Almost every valid Rust string is also a valid C string, but you have to make sure that the C string ends with a 0-character and that there are no 0-characters anywhere else in the string.
Rust provides a type that takes care of the conversion: CString.
If your input string was successfully converted to a CString you can simply copy the bytes without worrying about the details.
use std::slice;
use std::ffi::CString;
pub unsafe extern fn f(header_size: u32, header_ptr: *mut u8) -> i32 {
let headers = "abc";
let c_headers = match CString::new(headers) {
Ok(cs) => cs,
Err(_) => return -1, // failed to convert to C string
};
let bytes = c_headers.as_bytes_with_nul();
let header_bytes = slice::from_raw_parts_mut(header_ptr, header_size as usize);
header_bytes[..bytes.len()].copy_from_slice(bytes);
0 // success
}
fn main() {
let mut h = [1u8; 8];
unsafe {
f(h.len() as u32, h.as_mut_ptr());
}
println!("{:?}", h); // [97, 98, 99, 0, 1, 1, 1, 1]
}
Note that I left out the length check for brevity. header_bytes[..bytes.len()] will panic if the buffer is too short. This is something you will want to avoid if f is called from C.

How to reduce boilerplate nested Result in Rust

I have code using a nested Result like this:
fn ip4(s: &str) -> Result<(u8, u8, u8, u8), num::ParseIntError> {
let t: Vec<_> = s.split('.').collect();
match t[0].parse::<u8>() {
Ok(a1) => {
match t[1].parse::<u8>() {
Ok(a2) => {
match t[2].parse::<u8>() {
Ok(a3) => {
match t[3].parse::<u8>() {
Ok(a4) => {
Ok((a1, a2, a3, a4))
}
Err(er) => Err(er)
}
},
Err(er) => Err(er)
}
}
Err(er) => Err(er)
}
}
Err(er) => Err(er),
}
}
Is there any function or composing way to reduce this? Something like Haskell or Scala programmers do:
fn ip4(s: &str) -> Result<(u8, u8, u8, u8), num::ParseIntError> {
let t: Vec<_> = s.split('.').collect();
Result
.lift((,,,))
.ap(() -> t[0].parse::<u8>())
.ap(() -> t[1].parse::<u8>())
.ap(() -> t[2].parse::<u8>())
.ap(() -> t[3].parse::<u8>()) // maybe more concise in Haskell or Scala but I think it's enough :)
}
The answer to your direct question is the questionmark operator which would allow you to replace your whole match block with
Ok((
t[0].parse::<u8>()?,
t[1].parse::<u8>()?,
t[2].parse::<u8>()?,
t[3].parse::<u8>()?,
))
where essentially ? will return the error immediately if one is encountered.
That said, Rust already provides APIs for parsing IP addresses. Even if you wanted to maintain your tuple approach (though why would you), you could implement your function as
fn ip4(s: &str) -> Result<(u8, u8, u8, u8), net::AddrParseError> {
let addr: net::Ipv4Addr = s.parse()?;
let octets = addr.octets();
Ok((octets[0], octets[1], octets[2], octets[3]))
}
or just pass around the Ipv4Addr value directly.
Though, I do not see anything bad in #loganfsmyth's answer, I want to add another solution.
Your problem is a very simple and general problem of all programming languages which can be solved very easily if you would have enough time or practice in optimizing solutions. There is some divide and conquer recursive technique which is usually used to solve such problems. For a start, imagine a more simple thing: parsing a single octet from a string. This is a simple parse which you already know. Then mentally try to expand this problem to a larger one - parsing all octets which is a simple repeating process of the smallest problem we have solved earlier (parsing a single octet). This leads us to an iterative/recursive process: do something until. Keeping this in mind I have rewritten your function to a simple iterative process which uses tail-recursion which will not cause a stack overflow as a usual recursion due to it's form:
use std::num;
#[derive(Debug, Copy, Clone)]
struct IpAddressOctets(pub u8, pub u8, pub u8, pub u8);
type Result = std::result::Result<IpAddressOctets, num::ParseIntError>;
fn ipv4(s: &str) -> Result {
let octets_str_array: Vec<_> = s.split('.').collect();
// If it does not contain 4 octets then there is a error.
if octets_str_array.len() != 4 {
return Ok(IpAddressOctets(0, 0, 0, 0)) // or other error type
}
let octets = Vec::new();
fn iter_parse(octets_str_array: Vec<&str>, mut octets: Vec<u8>) -> Result {
if octets.len() == 4 {
return Ok(IpAddressOctets(octets[0], octets[1], octets[2], octets[3]))
}
let index = octets.len();
octets.push(octets_str_array[index].parse::<u8>()?);
iter_parse(octets_str_array, octets)
}
iter_parse(octets_str_array, octets)
}
fn main() {
println!("IP address octets parsed: {:#?}", ipv4("10.0.5.234"));
}
Keep in mind that Rust language is a bit more functional than you might think.
Also, I would recommend you to read this book which greatly explains the solution.
You can use early returns to prevent the nesting (but not the repetition).
Note the body of the Err arms of the matches:
fn ip4(s: &str) -> Result<(u8, u8, u8, u8), num::ParseIntError> {
let t: Vec<_> = s.split('.').collect();
let a1 = match t[0].parse::<u8>() {
Ok(x) => x,
Err(er) => return Err(er),
};
let a2 = match t[1].parse::<u8>() {
Ok(x) => x,
Err(er) => return Err(er),
};
let a3 = match t[2].parse::<u8>() {
Ok(x) => x,
Err(er) => return Err(er),
};
let a4 = match t[3].parse::<u8>() {
Ok(x) => x,
Err(er) => return Err(er),
};
(a1, a2, a3, a4)
}
But, as the others have said, Rust already has a built-in way to parse IP addresses.

Lifetime of format!() in match expression is too short

I am implementing a custom Display::fmt for my own struct which represent an interval.
struct Range<T> {
lower: Option<T>,
upper: Option<T>,
}
A range could be Range { lower: Some(1), upper: None }, which means it contains all integers from 1 up to infinity (or the limit of i32 I suppose).
I want to implement Display::fmt to use T's Display::fmt if the bound is not None and to display an empty string otherwise:
let range = Range { lower: Some(1), upper: None }
println!("{}", range); // Prints <1,>
let range = Range { lower: Some(1), upper: Some(10) }
println!("{}", range); // Prints <1,10>
let range = Range { lower: None, upper: Some(10) }
println!("{}", range); // Prints <,10>
I have started my implementation but have trouble with the match expression and the lifetime of the string produced by format!(). The problem with my implementation is that the string returned by format doesn't live long enough to be used further down.
fn main() {
let opt = Some(1);
let opt_display = match opt {
Some(x) => &format!("{}", x), // error: borrowed value does not live long enough
None => "",
};
println!("opt: {}", opt_display);
}
Why doesn't my approach work and what is a good solution to my problem?
I'm no expert on lifetimes, but I believe the problem here is that you are trying to return a &String from a String created by format! inside the match. Since the scope of the format is only inside the scope, the borrow checker complains.
To fix this you can use an owned string.
fn main() {
let opt = Some(1);
let opt_display = match opt {
Some(ref x) => format!("{}", x), // Allowed since opt_display now owns the string
None => "".into(),
};
// Another way to achieve the same thing.
//let opt_display = opt.map(|s| format!("{}", s)).unwrap_or("".into());
println!("opt: {}", opt_display);
}
When implementing Display, there's no need to return strings; you can just write!() into the provided formatter.
It would look like:
impl<T: Display> Display for Range<T> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), std::fmt::Error> {
write!(fmt, "<")?;
if let Some(v) = self.lower {
write!(fmt, "{}", v)?;
}
write!(fmt, ",")?;
if let Some(v) = self.upper {
write!(fmt, "{}", v)?;
}
write!(fmt, ">")
}
}
Playground
As Emilgardis has already explained, you are trying to return a reference to a value that will be dropped while the reference is still around. Congratulations, you just tried to create memory unsafety that would have caused a crash (or worse) in C or C++, but Rust prevented it!
One efficiency improvement you can make is to only allocate in one case:
fn main() {
let opt = Some(1);
let opt_display = opt.map(|s| format!("{}", s));
// Type not needed, only used to assert the type is what we expect
let opt_display_str: &str = opt_display.as_ref().map(String::as_str).unwrap_or("");
println!("opt: {}", opt_display_str);
}
You could also use a Cow, which allows either an owned or borrowed string. Note how similar it is to the other answer, but this doesn't allocate in the case of None:
use std::borrow::Cow;
fn main() {
let opt = Some(1);
let opt_display: Cow<str> = match opt {
Some(ref x) => format!("{}", x).into(),
None => "".into(),
};
println!("opt: {}", opt_display);
}
I want to implement Display::fmt
The best thing to do is probably to avoid any allocation then. You will be handed a formatter that you write! to, just call write! in each match arm. This might introduce a bit of duplication, but is probably more efficient. Without the formatter, it would look something like:
fn main() {
let opt = Some(1);
print!("opt: ");
if let Some(ref x) = opt {
print!("{}", x);
}
println!("");
}
Substitute write!(f, for print!( inside the formatter and return on error.

Resources