Search code examples
rustrefreference-countingrefcell

Peekable content is None after refactor the code


I have this method:

fn parse_http_request_headers<'b>(sp: &'b mut std::str::Split<&str>) -> HashMap<String, String> {
        let mut headers: HashMap<String, String> = HashMap::new();
        let mut iter = sp.peekable();

        while iter.peek() != None {
            let next = iter.next();
            if let Some(value_to_parse) = next {
                let parts = value_to_parse.split(": ").collect::<Vec<&str>>();
                let key = parts.get(0);
                if parts.len() == 2 {
                    headers.insert(
                        (*key.expect(&format!("Error getting the header definition: {:?}", &key)))
                            .to_string(), 
                        (*parts.get(1)
                            .expect(&format!("Error getting the header value from: {:?}", &parts)))
                            .to_string()
                    );
                }
            } else { iter.next(); }
        }

        headers
    }

that I refactored for curiosity about playing with the Interior mutability pattern, to try to solve some doubts about struct's fields that contains references. But, ok, let's go with the code:

fn parse_http_request_headers<'b>(sp: Rc<RefCell<&'b mut std::str::Split<&str>>>) -> HashMap<String, String> {
        
        let mut headers: HashMap<String, String> = HashMap::new();
        let mut borrow = sp.borrow_mut();  // let binding
        
        let mut iter = borrow.peekable();
        
        while iter.peek() != None {
            
            let next = iter.next();
            if let Some(value_to_parse) = next {
                let parts = value_to_parse.split(": ").collect::<Vec<&str>>();
                let key = parts.get(0);
                if parts.len() == 2 {
                    headers.insert(
                        (*key.expect(&format!("Error getting the header definition: {:?}", &key)))
                            .to_string(), 
                        (*parts.get(1)
                            .expect(&format!("Error getting the header value from: {:?}", &parts)))
                            .to_string()
                    );
                }
            } else { iter.next(); }
        }
        headers
    }

But, for my surprise, there's no iterations over the peekable peeked: None.

Why is causing this?

The first version works perfect parsing the http headers, this is the output:

HttpRequest { verb: GET, uri: Uri { uri: "/" }, http_version: V1_1, headers: {"Sec-Fetch-Mode": "navigate", "Connection": "keep-alive", "DNT": "1", "Sec-Fetch-Site": "none", "Host": "127.0.0.1:7878", "Sec-GPC": "1", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate, br", "Sec-Fetch-Dest": "document"}, body: None }

The calling code:

let rc: Rc<RefCell<&mut Split<&str>>> = Rc::new(RefCell::new(sp));
        
let (verb, uri, version) = Self::parse_verb_uri_version(Rc::clone(&rc));
let body = Self::parse_http_request_body(Rc::clone(&rc).borrow_mut().last().unwrap());
let headers = Self::parse_http_request_headers(Rc::clone(&rc));

where sp: sp: &'a mut Split<&'a str>

Thanks.


Solution

  • You use .last() in the proceeding line which will consume all elements from the iterator leaving nothing behind to iterate in parse_http_request_headers().