0
votes

This is a two-parter.

Ideally I'd like to implement the FromStr trait, but with or without that, I need to implement from_str().

A CqlString consists of a u16 (two u8s) followed by the raw bytes of the original string.

The version below generates "error: 'bytes' does not live long enough", so that's problem #1. If I make it "impl FromStr for CqlString", then I get an earlier error of: error: method from_str has an incompatible type for trait: expected concrete lifetime, found bound lifetime parameter [E0053]

So given the structure of CqlString, how can I implement a FromStr fn properly?

#[repr(C, packed)] 
pub struct CqlString<'a>(&'a [u8]);

impl<'a> CqlString<'a>  {
    fn from_str(s: &str) -> Option<CqlString> {
        let mut bytes = Vec::<u8>::new();
        bytes.push_all(unsafe{Utils::raw_byte_repr(&s.len().to_u16())}); //convert the hashmap length to a a two byte short and start building our &[u8]
        bytes.push_all(s.as_bytes());
        let cqls = CqlString(bytes[]);
        Some(cqls)
    }
}
1

1 Answers

3
votes

The short answer is that you can't. CqlString contains a reference to other data, but FromStr expects to create a fully-owned object that no longer needs to reference the &str. These two concepts are incompatible.

The closest I can see is that you could create an OwnedCqlString:

struct OwnedCqlString {
    data: Vec<u8>,
}

impl OwnedCqlString {
    fn as_cql_string(&self) -> CqlString { CqlString(self.data.as_slice()) }
}

impl FromStr for OwnedCqlString {
    fn from_str(s: &str) -> Option<OwnedCqlString> {
        // logic here
    }
}

fn main() {
    let ocs: OwnedCqlString = "hello".parse();
    let cs = ocs.as_cql_string();
}

Ultimately, this comes down to two questions:

  1. Where are you going to store the bytes that represent the size?
  2. How do you ensure that those bytes immediately precede the string data in memory?

An alternate idea

If you didn't need to store the slice of bytes, but instead could have a "streaming" interface, then you could implement that directly on &str:

trait WriteCqlStr {
    fn write_to<W>(&self, &mut W)
        where W: Writer; 
}

impl WriteCqlStr for CqlStr {
    // Straight-forward impl, write the bytes we refer to
}

impl<'a> WriteCqlStr for &'a str {
    // Write the length, then write the bytes of the str
}