1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
//! Rust bindings for Unidata's [libnetcdf] (http://www.unidata.ucar.edu/software/netcdf/) //! //! # Examples //! //! Read: //! //! ``` //! # let path_to_simple_xy = netcdf::test_file("simple_xy.nc"); //! // Open file simple_xy.nc: //! let file = netcdf::open(&path_to_simple_xy).unwrap(); //! //! // Access any variable, attribute, or dimension through simple HashMap's: //! let var = file.root.variables.get("data").unwrap(); //! //! // Read variable as any NC_TYPE, optionally failing if doing so would //! // force a cast: //! let data : Vec<i32> = var.get_int(false).unwrap(); //! //! // You can also use values() to read the variable, data will be implicitly casted //! // if needed //! let data : Vec<i32> = var.values().unwrap(); //! //! // All variable data is read into 1-dimensional Vec. //! for x in 0..(6*12) { //! assert_eq!(data[x], x as i32); //! } //! ``` //! //! Write: //! //! ``` //! // Write //! let f = netcdf::test_file_new("crabs2.nc"); // just gets a path inside repo //! { //! let mut file = netcdf::create(&f).unwrap(); //! //! let dim_name = "ncrabs"; //! file.root.add_dimension(dim_name, 10).unwrap(); //! //! let var_name = "crab_coolness_level"; //! let data : Vec<i32> = vec![42; 10]; //! // Variable type written to file is inferred from Vec type: //! file.root.add_variable( //! var_name, //! &vec![dim_name.to_string()], //! &data //! ).unwrap(); //! } //! //! // Append: //! { //! // You can also modify a Variable inside an existing netCDF file //! // open it in read/write mode //! let mut file = netcdf::append(&f).unwrap(); //! // get a mutable binding of the variable "crab_coolness_level" //! let mut var = file.root.variables.get_mut("crab_coolness_level").unwrap(); //! //! let data : Vec<i32> = vec![100; 10]; //! // write 5 first elements of the vector `data` into `var` starting at index 2; //! var.put_values_at(&data, &[2], &[5]); //! // Change the first value of `var` into '999' //! var.put_value_at(999 as f32, &[0]); //! } //! ``` extern crate netcdf_sys; extern crate ndarray; #[macro_use] extern crate lazy_static; extern crate libc; use netcdf_sys::{libnetcdf_lock, nc_strerror}; use std::ffi; use std::str; use std::path; use std::env; use std::fs; use std::collections::HashMap; pub mod file; pub mod variable; pub mod attribute; pub mod group; pub mod dimension; pub use file::open; pub use file::create; pub use file::append; fn string_from_c_str(c_str: &ffi::CStr) -> String { // see http://stackoverflow.com/questions/24145823/rust-ffi-c-string-handling // for good rundown let buf: &[u8] = c_str.to_bytes(); let str_slice: &str = str::from_utf8(buf).unwrap(); str_slice.to_owned() } lazy_static! { pub static ref NC_ERRORS: HashMap<i32, String> = { let mut m = HashMap::new(); // Invalid error codes are ok; nc_strerror will just return // "Unknown Error" for i in -256..256 { let msg_cstr : &ffi::CStr; unsafe { let _g = libnetcdf_lock.lock().unwrap(); let msg : *const i8 = nc_strerror(i); msg_cstr = &ffi::CStr::from_ptr(msg); } m.insert(i, string_from_c_str(msg_cstr)); } m }; } // Helpers for getting file paths pub fn test_file(f: &str) -> String { let mnf_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let path = path::Path::new(&mnf_dir).join( "testdata").join(f); path.to_str().unwrap().to_string() } pub fn test_file_new(f: &str) -> String { let mnf_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let path = path::Path::new(&mnf_dir).join("testout"); let new_file = path.join(f); let _err = fs::create_dir(path); new_file.to_str().unwrap().to_string() }