2

I'm trying to read input from the user, and then use it as the URL for the POP3 library. When converting the String that I get to a string slice, it doesn't live long enough to be used. This is strange to me for two reasons:

  1. Because everything that uses the POP3 object is inside the same block, so the lifetime of the str slice should be that of the entire block, which would cover everything

  2. I've tried almost every different code configuration I could think of, and to no avail, I get the same error every time.

extern crate pop3;
extern crate smtp;
extern crate openssl;
extern crate libc;

use openssl::ssl::{SslContext, SslMethod};
use pop3::POP3Stream;
use pop3::POP3Result::{POP3Stat, POP3List, POP3Message};

mod readline;
use readline::*;

fn main() {
    let place = match readline("URL: ") {             // Problem line
        Some(input) => {                              // Problem line
            let place: &'static str = &input[..];     // Problem line
            let mut email_socket = match POP3Stream::connect(place, 995, Some(SslContext::new(SslMethod::Sslv23).unwrap())) { // Problem line
                Ok(s) => s,
                Err(e) => panic!("{}", e)
            };

            match readline("Username: ") {
                Some(username) => {
                    match readline("Password: ") {
                        Some(password) => { email_socket.login(&*username, &*password); },
                        None           => println!("Please enter a password.")
                    }
                },
                None           => println!("Please enter a username.")
            };

            let stat = email_socket.stat();
            match stat {
                POP3Stat {num_email,
                          mailbox_size} => println!("num_email: {},  mailbox_size:{}", num_email, mailbox_size),
                e => println!("There was an error signing into your server."),
            }

            let list_all = email_socket.list(None);
            match list_all {
                POP3List {emails_metadata} => {
                    for i in emails_metadata.iter() {
                        println!("message_id: {},  message_size: {}", i.message_id, i.message_size);
                    }
                },
                _ => println!("There was an error listing your messages."),
            }

            let message_25 = email_socket.retr(25);
            match message_25 {
                POP3Message{raw} => {
                    for i in raw.iter() {
                        println!("{}", i);
                    }
                },
                _ => println!("There was an error getting your 25th message."),
            }

            email_socket.quit();
        },
        None        => { println!("Please enter a URL for your server."); }
    };
}
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
Alexis Dumas
  • 1,299
  • 11
  • 30
  • Your last edit completely changed your question, invalidating the two present answers, so I'm going to roll it back. You are welcome to ask another question now that you know what you want to ask, but one of the present answers likely addresses the question you posed. – Shepmaster Oct 08 '15 at 14:58
  • Ok. Sorry, I will ask a new question, now that I have a more clear idea of what I'm doing. By the way, your answer does not actually fix the code in my question, and I can't seem to find an MCVE that perfectly reproduces my error. – Alexis Dumas Oct 08 '15 at 15:01
  • Sounds good! I guarantee we will get to the bottom of your problem, but it might take some twists and turns along the way as we all learn :-) – Shepmaster Oct 08 '15 at 15:02

1 Answers1

2

The Problem

Your problem boils down to the use of static since the keyword basically says "keep this object around forever". This means that the lifetime of place, without a doubt, will live long after input — forever vs the scope of the block.

fn get() -> Option<String> {
    Some("hello world".to_owned())
}
fn main() {
    let data = match get() {
        Some(input) => { let place : &'static str = &input[..]; },
        None        => { }
    };
}

In the above we try to make place a static reference to a str, other other words; a reference that exists for the entire duration of our program. input on the other hand will definitely not exist for this amount of time, and therefor we get an error diagnostic.

<anon>:7:54: 7:59 error: `input` does not live long enough
<anon>:7         Some(input) => { let place : &'static str = &input[..]; },

The Solution

Remove the use of static, effectively saying that the lifetime of place is that of the block (which is a subset of the lifetime associated with input).

fn get() -> Option<String> {
    Some("hello world".to_owned())
}
fn main() {
    let data = match get() {
        Some(input) => { let place : &str = &input[..]; },
        None        => { }
    };   
}


Further Digging

As it turns out, POP3Stream::connect accepts a &'static str as its first argument; this is really bad design since it will only accept string-literals.

impl Pop3Stream {
    pub fn connect(host: &'static str, ...) -> Result<POP3Stream> {
        ...
    }
}

You can, however, hack your way around the issue by intentionally leaking the resource—effectively making it live "forever". Please note the usage of unsafe, and keep in mind that this is—by language design—considered to be just that.

fn get () -> Option<String> {
  Some("hello world".to_owned ())
}
fn connect (host : &'static str) {
  /* ... */
}
fn main() { 
    let data = match get() {
        Some(input) => {
            let place : &'static str = unsafe {
                use std::mem; let x = mem::transmute(&input as &str);
                mem::forget (x);  x
            };  

            connect(place);
        },
        None => { }
    };   
}
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196