jefftime
jefftime

Reputation: 440

Rust "if let" not working?

I am wrapping libxml2 in Rust as an exercise in learning the Rust FFI, and I have come across something strange. I am new to Rust, but I believe the following should work.

In main.rs I have:

mod xml;

fn main() {
    if let doc = xml::parse_file("filename") {
        doc.simple_function();
    }
}

And xml.rs is:

extern create libc;

use libc::{c_void, c_char, c_int, c_ushort};
use std::ffi::CString;

// There are other struct definitions I've implemented that xmlDoc
// depends on, but I'm not going to list them because I believe
// they're irrelevant

#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[repr(C)]
struct xmlDoc {
    // xmlDoc structure defined by the libxml2 API
}


pub struct Doc {
    ptr: *mut xmlDoc
}

impl Doc {
    pub fn simple_function(&self) {
        if self.ptr.is_null() {
            println!("ptr doesn't point to anything");
        } else {
            println!("ptr is not null");
        }
    }
}

#[allow(non_snake_case)]
#[link(name = "xml2")]
extern {
    fn xmlParseFile(filename: *const c_char) -> *mut xmlDoc;
}

pub fn parse_file(filename: &str) -> Option<Doc> {
    unsafe {
        let result;
        match CString::new(filename) {
            Ok(f) => { result = xmlParseFile(f.as_ptr()); },
            Err(_) => { return None; }
        }
        if result.is_null() {
            return None;
        }
        Some(Doc { ptr: result })
    }
}

I'm wrapping the C struct, xmlDoc in a nice Rust-friendly struct, Doc, to have a clear delineation between the safe (Rust) and unsafe (C) data types and functions.

This all works for the most part except when I compile, I get an error in main.rs:

src/main.rs:38:13: 38:28 error: no method named 'simple_function' found
for type 'std::option::Option<xml::Doc>' in the current scope
src/main.rs:38         doc.simple_function();
                       ^~~~~~~~~~~~~~~
error: aborting due to previous error`

It seems convinced that doc is an Option<xml::Doc> even though I'm using the if let form that should unwrap the Option type. Is there something I'm doing incorrectly?

match xml::parse_file("filename") {
    Some(doc) => doc.simple_function(),
    None => {}
}

The above works fine, but I'd like to use the if let feature of Rust if I'm able.

Upvotes: 2

Views: 822

Answers (1)

Dogbert
Dogbert

Reputation: 222118

You need to pass the actual pattern to if let (unlike languages like Swift which special case if let for Option types):

if let Some(doc) = xml::parse_file("filename") {
    doc.simple_function();
}

Upvotes: 8

Related Questions