Musicpulpite
Musicpulpite

Reputation: 11

The correct way to annotate lifetimes/ determine ownership of strings in a method?

just starting out on my adventures in Rust and trying to figure out the right way to create and return an enum that should take ownership of a &str string slice created from a String passed into the method. I don't think lifetime annotations in and of themselves will solve the problem since the original string argument will go out of scope at the end of the function block regardless. Any help would be much appreciated.

pub enum PubSubMessage {
    // For now I won't worry about subbing/unsubbing to an array of channels
    SUBSCRIBE { channel: &str },
    UNSUBSCRIBE { channel: &str },
    PUBLISH { channel: &str, msg: &str},
    PSUBSCRIBE { pattern: &str },
    PUNSUBSCRIBE { pattern: &str},
}

pub fn parse_message(msg: String) -> Result<PubSubMessage, String> {
    let msg_contents: Vec<&str> = msg.split(" ").collect();

    return match msg_contents.as_slice() {
        ["SUBSCRBE", channel] => Ok(PubSubMessage::SUBSCRIBE { channel }),
        ["UNSUBSCRIBE", channel] => Ok(PubSubMessage::UNSUBSCRIBE { channel }),
        ["PUBLISH", channel, msg] => Ok(PubSubMessage::PUBLISH { channel, msg }),
        _ => Err("Could not parse ws message.".to_string())
    }
}

The current compiler error that I'm getting is just that the enum definition expects lifetime parameters.

Upvotes: 0

Views: 115

Answers (1)

Jmb
Jmb

Reputation: 23414

As others have said in the comments, the easiest way to do it is to use String everywhere. That being said, if you wan to avoid extra copies and allocations, you can push the responsibility for owning the string higher up the call chain. If you want to do that, you will need to change your function signature so that it borrows msg instead of taking ownership, and add the required lifetime parameters. Something like this:

pub enum PubSubMessage<'a> {
    // For now I won't worry about subbing/unsubbing to an array of channels
    SUBSCRIBE { channel: &'a str },
    UNSUBSCRIBE { channel: &'a str },
    PUBLISH { channel: &'a str, msg: &'a str},
    PSUBSCRIBE { pattern: &'a str },
    PUNSUBSCRIBE { pattern: &'a str},
}

pub fn parse_message<'a> (msg: &'a str) -> Result<PubSubMessage<'a>, String> {
    let msg_contents: Vec<_> = msg.split(" ").collect();

    return match msg_contents.as_slice() {
        ["SUBSCRBE", channel] => Ok(PubSubMessage::SUBSCRIBE { channel }),
        ["UNSUBSCRIBE", channel] => Ok(PubSubMessage::UNSUBSCRIBE { channel }),
        ["PUBLISH", channel, msg] => Ok(PubSubMessage::PUBLISH { channel, msg }),
        _ => Err("Could not parse ws message.".to_string())
    }
}

Playground

Upvotes: 2

Related Questions