Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
208 views
in Technique[技术] by (71.8m points)

rust - Implementing FromStr for a custom &[u8] type

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)
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...