Skip to main content

dta/
lib.rs

1#![warn(missing_docs)]
2
3//! A pure Rust reader and writer for Stata's DTA file format.
4//!
5//! DTA is the binary format [Stata](https://www.stata.com/) uses to
6//! persist datasets. This crate covers every released version of the
7//! format (104 through 119), including XML-framed releases (117+),
8//! tagged missing values, value-label sets, and long-string (`strL`)
9//! storage.
10//!
11//! The API is built around a typestate chain — you walk through the
12//! sections of a file in order, and each phase hands the underlying
13//! I/O handle to the next. See the [README] for the full tour.
14//!
15//! [README]: https://github.com/almus-the-dan/dta/#readme
16//!
17//! # Reading a DTA file
18//!
19//! ```no_run
20//! use dta::stata::dta::dta_reader::DtaReader;
21//! use dta::stata::dta::dta_error::Result;
22//!
23//! # fn demo() -> Result<()> {
24//! let mut characteristic_reader = DtaReader::new()
25//!     .from_path("example.dta")?
26//!     .read_header()?
27//!     .read_schema()?;
28//!
29//! // Characteristics are optional — skip them if you don't care.
30//! characteristic_reader.skip_to_end()?;
31//!
32//! // Iterate observation rows.
33//! let mut record_reader = characteristic_reader.into_record_reader()?;
34//! let schema = record_reader.schema().clone();
35//! while let Some(record) = record_reader.read_record()? {
36//!     for (variable, value) in schema.variables().iter().zip(record.values()) {
37//!         println!("{}: {:?}", variable.name(), value);
38//!     }
39//! }
40//! # Ok(())
41//! # }
42//! ```
43//!
44//! # Writing a DTA file
45//!
46//! ```no_run
47//! use dta::stata::dta::byte_order::ByteOrder;
48//! use dta::stata::dta::dta_error::Result;
49//! use dta::stata::dta::dta_writer::DtaWriter;
50//! use dta::stata::dta::header::Header;
51//! use dta::stata::dta::release::Release;
52//! use dta::stata::dta::schema::Schema;
53//! use dta::stata::dta::value::Value;
54//! use dta::stata::dta::variable::Variable;
55//! use dta::stata::dta::variable_type::VariableType;
56//! use dta::stata::stata_long::StataLong;
57//!
58//! # fn demo() -> Result<()> {
59//! let header = Header::builder(Release::V118, ByteOrder::LittleEndian).build();
60//! let schema = Schema::builder()
61//!     .add_variable(Variable::builder(VariableType::Long, "id").format("%12.0g"))
62//!     .build()?;
63//!
64//! let mut record_writer = DtaWriter::new()
65//!     .from_path("example.dta")?
66//!     .write_header(header)?
67//!     .write_schema(schema)?
68//!     .into_record_writer()?;
69//! record_writer.write_record(&[Value::Long(StataLong::Present(1))])?;
70//!
71//! record_writer
72//!     .into_long_string_writer()?
73//!     .into_value_label_writer()?
74//!     .finish()?;
75//! # Ok(())
76//! # }
77//! ```
78//!
79//! # Round-trip (runnable)
80//!
81//! Both sides together against an in-memory buffer, so this example
82//! actually executes in the test harness:
83//!
84//! ```
85//! use std::io::Cursor;
86//! use dta::stata::dta::byte_order::ByteOrder;
87//! use dta::stata::dta::dta_error::Result;
88//! use dta::stata::dta::dta_reader::DtaReader;
89//! use dta::stata::dta::dta_writer::DtaWriter;
90//! use dta::stata::dta::header::Header;
91//! use dta::stata::dta::release::Release;
92//! use dta::stata::dta::schema::Schema;
93//! use dta::stata::dta::value::Value;
94//! use dta::stata::dta::variable::Variable;
95//! use dta::stata::dta::variable_type::VariableType;
96//! use dta::stata::stata_long::StataLong;
97//!
98//! # fn demo() -> Result<()> {
99//! let header = Header::builder(Release::V118, ByteOrder::LittleEndian).build();
100//! let schema = Schema::builder()
101//!     .add_variable(Variable::builder(VariableType::Long, "id").format("%12.0g"))
102//!     .build()?;
103//!
104//! let mut record_writer = DtaWriter::new()
105//!     .from_writer(Cursor::new(Vec::<u8>::new()))
106//!     .write_header(header)?
107//!     .write_schema(schema)?
108//!     .into_record_writer()?;
109//! record_writer.write_record(&[Value::Long(StataLong::Present(42))])?;
110//! let bytes = record_writer
111//!     .into_long_string_writer()?
112//!     .into_value_label_writer()?
113//!     .finish()?
114//!     .into_inner();
115//!
116//! let mut characteristic_reader = DtaReader::new()
117//!     .from_reader(Cursor::new(bytes))
118//!     .read_header()?
119//!     .read_schema()?;
120//! characteristic_reader.skip_to_end()?;
121//! let mut record_reader = characteristic_reader.into_record_reader()?;
122//! let record = record_reader.read_record()?.unwrap();
123//! assert_eq!(record.values().len(), 1);
124//! # Ok(())
125//! # }
126//! # demo().unwrap();
127//! ```
128//!
129//! # Async
130//!
131//! Enable the `tokio` feature for async reader and writer mirrors —
132//! same typestate chain, `.await` at each step. `DtaReader::from_tokio_*`
133//! / `DtaWriter::from_tokio_*` are the entry points.
134
135/// Stata file format types and utilities.
136pub mod stata;