/rust/registry/src/index.crates.io-6f17d22bba15001f/gimli-0.26.2/src/write/mod.rs
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | //! Write DWARF debugging information. | 
| 2 |  | //! | 
| 3 |  | //! ## API Structure | 
| 4 |  | //! | 
| 5 |  | //! This module works by building up a representation of the debugging information | 
| 6 |  | //! in memory, and then writing it all at once. It supports two major use cases: | 
| 7 |  | //! | 
| 8 |  | //! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF | 
| 9 |  | //! for a single compilation unit. | 
| 10 |  | //! | 
| 11 |  | //! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple | 
| 12 |  | //! compilation units. | 
| 13 |  | //! | 
| 14 |  | //! The module also supports reading in DWARF debugging information and writing it out | 
| 15 |  | //! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html) | 
| 16 |  | //! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert | 
| 17 |  | //! it to a writable instance. | 
| 18 |  | //! | 
| 19 |  | //! ## Example Usage | 
| 20 |  | //! | 
| 21 |  | //! Write a compilation unit containing only the top level DIE. | 
| 22 |  | //! | 
| 23 |  | //! ```rust | 
| 24 |  | //! use gimli::write::{ | 
| 25 |  | //!     Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections, | 
| 26 |  | //! }; | 
| 27 |  | //! | 
| 28 |  | //! fn example() -> Result<(), Error> { | 
| 29 |  | //!     // Choose the encoding parameters. | 
| 30 |  | //!     let encoding = gimli::Encoding { | 
| 31 |  | //!         format: gimli::Format::Dwarf32, | 
| 32 |  | //!         version: 5, | 
| 33 |  | //!         address_size: 8, | 
| 34 |  | //!     }; | 
| 35 |  | //!     // Create a container for a single compilation unit. | 
| 36 |  | //!     let mut dwarf = DwarfUnit::new(encoding); | 
| 37 |  | //!     // Set a range attribute on the root DIE. | 
| 38 |  | //!     let range_list = RangeList(vec![Range::StartLength { | 
| 39 |  | //!         begin: Address::Constant(0x100), | 
| 40 |  | //!         length: 42, | 
| 41 |  | //!     }]); | 
| 42 |  | //!     let range_list_id = dwarf.unit.ranges.add(range_list); | 
| 43 |  | //!     let root = dwarf.unit.root(); | 
| 44 |  | //!     dwarf.unit.get_mut(root).set( | 
| 45 |  | //!         gimli::DW_AT_ranges, | 
| 46 |  | //!         AttributeValue::RangeListRef(range_list_id), | 
| 47 |  | //!     ); | 
| 48 |  | //!     // Create a `Vec` for each DWARF section. | 
| 49 |  | //!     let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian)); | 
| 50 |  | //!     // Finally, write the DWARF data to the sections. | 
| 51 |  | //!     dwarf.write(&mut sections)?; | 
| 52 |  | //!     sections.for_each(|id, data| { | 
| 53 |  | //!         // Here you can add the data to the output object file. | 
| 54 |  | //!         Ok(()) | 
| 55 |  | //!     }) | 
| 56 |  | //! } | 
| 57 |  | //! # fn main() { | 
| 58 |  | //! #     example().unwrap(); | 
| 59 |  | //! # } | 
| 60 |  |  | 
| 61 |  | use std::error; | 
| 62 |  | use std::fmt; | 
| 63 |  | use std::result; | 
| 64 |  |  | 
| 65 |  | use crate::constants; | 
| 66 |  |  | 
| 67 |  | mod endian_vec; | 
| 68 |  | pub use self::endian_vec::*; | 
| 69 |  |  | 
| 70 |  | mod writer; | 
| 71 |  | pub use self::writer::*; | 
| 72 |  |  | 
| 73 |  | #[macro_use] | 
| 74 |  | mod section; | 
| 75 |  | pub use self::section::*; | 
| 76 |  |  | 
| 77 |  | macro_rules! define_id { | 
| 78 |  |     ($name:ident, $docs:expr) => { | 
| 79 |  |         #[doc=$docs] | 
| 80 |  |         #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 
| 81 |  |         pub struct $name { | 
| 82 |  |             base_id: BaseId, | 
| 83 |  |             index: usize, | 
| 84 |  |         } | 
| 85 |  |  | 
| 86 |  |         impl $name { | 
| 87 |  |             #[inline] | 
| 88 | 28.4k |             fn new(base_id: BaseId, index: usize) -> Self { | 
| 89 | 28.4k |                 $name { base_id, index } | 
| 90 | 28.4k |             } <gimli::write::cfi::CieId>::new| Line | Count | Source |  | 88 | 28.4k |             fn new(base_id: BaseId, index: usize) -> Self { |  | 89 | 28.4k |                 $name { base_id, index } |  | 90 | 28.4k |             } | 
Unexecuted instantiation: <gimli::write::loc::LocationListId>::newUnexecuted instantiation: <gimli::write::range::RangeListId>::newUnexecuted instantiation: <gimli::write::unit::UnitId>::newUnexecuted instantiation: <gimli::write::unit::UnitEntryId>::newUnexecuted instantiation: <gimli::write::str::StringId>::newUnexecuted instantiation: <gimli::write::str::LineStringId>::new | 
| 91 |  |         } | 
| 92 |  |     }; | 
| 93 |  | } | 
| 94 |  |  | 
| 95 |  | macro_rules! define_offsets { | 
| 96 |  |     ($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => { | 
| 97 |  |         #[doc=$off_doc] | 
| 98 |  |         #[derive(Debug)] | 
| 99 |  |         pub struct $offsets { | 
| 100 |  |             base_id: BaseId, | 
| 101 |  |             // We know ids start at 0. | 
| 102 |  |             offsets: Vec<$offset>, | 
| 103 |  |         } | 
| 104 |  |  | 
| 105 |  |         impl $offsets { | 
| 106 |  |             /// Return an empty list of offsets. | 
| 107 |  |             #[inline] | 
| 108 | 0 |             pub fn none() -> Self { | 
| 109 | 0 |                 $offsets { | 
| 110 | 0 |                     base_id: BaseId::default(), | 
| 111 | 0 |                     offsets: Vec::new(), | 
| 112 | 0 |                 } | 
| 113 | 0 |             } Unexecuted instantiation: <gimli::write::loc::LocationListOffsets>::noneUnexecuted instantiation: <gimli::write::range::RangeListOffsets>::noneUnexecuted instantiation: <gimli::write::str::DebugStrOffsets>::noneUnexecuted instantiation: <gimli::write::str::DebugLineStrOffsets>::none | 
| 114 |  |  | 
| 115 |  |             /// Get the offset | 
| 116 |  |             /// | 
| 117 |  |             /// # Panics | 
| 118 |  |             /// | 
| 119 |  |             /// Panics if `id` is invalid. | 
| 120 |  |             #[inline] | 
| 121 | 0 |             pub fn get(&self, id: $id) -> $offset { | 
| 122 | 0 |                 debug_assert_eq!(self.base_id, id.base_id); | 
| 123 | 0 |                 self.offsets[id.index] | 
| 124 | 0 |             } Unexecuted instantiation: <gimli::write::loc::LocationListOffsets>::getUnexecuted instantiation: <gimli::write::range::RangeListOffsets>::getUnexecuted instantiation: <gimli::write::str::DebugStrOffsets>::getUnexecuted instantiation: <gimli::write::str::DebugLineStrOffsets>::get | 
| 125 |  |  | 
| 126 |  |             /// Return the number of offsets. | 
| 127 |  |             #[inline] | 
| 128 | 0 |             pub fn count(&self) -> usize { | 
| 129 | 0 |                 self.offsets.len() | 
| 130 | 0 |             } Unexecuted instantiation: <gimli::write::loc::LocationListOffsets>::countUnexecuted instantiation: <gimli::write::range::RangeListOffsets>::countUnexecuted instantiation: <gimli::write::str::DebugStrOffsets>::countUnexecuted instantiation: <gimli::write::str::DebugLineStrOffsets>::count | 
| 131 |  |         } | 
| 132 |  |     }; | 
| 133 |  | } | 
| 134 |  |  | 
| 135 |  | mod abbrev; | 
| 136 |  | pub use self::abbrev::*; | 
| 137 |  |  | 
| 138 |  | mod cfi; | 
| 139 |  | pub use self::cfi::*; | 
| 140 |  |  | 
| 141 |  | mod dwarf; | 
| 142 |  | pub use self::dwarf::*; | 
| 143 |  |  | 
| 144 |  | mod line; | 
| 145 |  | pub use self::line::*; | 
| 146 |  |  | 
| 147 |  | mod loc; | 
| 148 |  | pub use self::loc::*; | 
| 149 |  |  | 
| 150 |  | mod op; | 
| 151 |  | pub use self::op::*; | 
| 152 |  |  | 
| 153 |  | mod range; | 
| 154 |  | pub use self::range::*; | 
| 155 |  |  | 
| 156 |  | mod str; | 
| 157 |  | pub use self::str::*; | 
| 158 |  |  | 
| 159 |  | mod unit; | 
| 160 |  | pub use self::unit::*; | 
| 161 |  |  | 
| 162 |  | /// An error that occurred when writing. | 
| 163 |  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 
| 164 |  | pub enum Error { | 
| 165 |  |     /// The given offset is out of bounds. | 
| 166 |  |     OffsetOutOfBounds, | 
| 167 |  |     /// The given length is out of bounds. | 
| 168 |  |     LengthOutOfBounds, | 
| 169 |  |     /// The attribute value is an invalid for writing. | 
| 170 |  |     InvalidAttributeValue, | 
| 171 |  |     /// The value is too large for the encoding form. | 
| 172 |  |     ValueTooLarge, | 
| 173 |  |     /// Unsupported word size. | 
| 174 |  |     UnsupportedWordSize(u8), | 
| 175 |  |     /// Unsupported DWARF version. | 
| 176 |  |     UnsupportedVersion(u16), | 
| 177 |  |     /// The unit length is too large for the requested DWARF format. | 
| 178 |  |     InitialLengthOverflow, | 
| 179 |  |     /// The address is invalid. | 
| 180 |  |     InvalidAddress, | 
| 181 |  |     /// The reference is invalid. | 
| 182 |  |     InvalidReference, | 
| 183 |  |     /// A requested feature requires a different DWARF version. | 
| 184 |  |     NeedVersion(u16), | 
| 185 |  |     /// Strings in line number program have mismatched forms. | 
| 186 |  |     LineStringFormMismatch, | 
| 187 |  |     /// The range is empty or otherwise invalid. | 
| 188 |  |     InvalidRange, | 
| 189 |  |     /// The line number program encoding is incompatible with the unit encoding. | 
| 190 |  |     IncompatibleLineProgramEncoding, | 
| 191 |  |     /// Could not encode code offset for a frame instruction. | 
| 192 |  |     InvalidFrameCodeOffset(u32), | 
| 193 |  |     /// Could not encode data offset for a frame instruction. | 
| 194 |  |     InvalidFrameDataOffset(i32), | 
| 195 |  |     /// Unsupported eh_frame pointer encoding. | 
| 196 |  |     UnsupportedPointerEncoding(constants::DwEhPe), | 
| 197 |  |     /// Unsupported reference in CFI expression. | 
| 198 |  |     UnsupportedCfiExpressionReference, | 
| 199 |  |     /// Unsupported forward reference in expression. | 
| 200 |  |     UnsupportedExpressionForwardReference, | 
| 201 |  | } | 
| 202 |  |  | 
| 203 |  | impl fmt::Display for Error { | 
| 204 | 0 |     fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { | 
| 205 | 0 |         match *self { | 
| 206 | 0 |             Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."), | 
| 207 | 0 |             Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."), | 
| 208 |  |             Error::InvalidAttributeValue => { | 
| 209 | 0 |                 write!(f, "The attribute value is an invalid for writing.") | 
| 210 |  |             } | 
| 211 | 0 |             Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."), | 
| 212 | 0 |             Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size), | 
| 213 | 0 |             Error::UnsupportedVersion(version) => { | 
| 214 | 0 |                 write!(f, "Unsupported DWARF version: {}", version) | 
| 215 |  |             } | 
| 216 | 0 |             Error::InitialLengthOverflow => write!( | 
| 217 | 0 |                 f, | 
| 218 | 0 |                 "The unit length is too large for the requested DWARF format." | 
| 219 | 0 |             ), | 
| 220 | 0 |             Error::InvalidAddress => write!(f, "The address is invalid."), | 
| 221 | 0 |             Error::InvalidReference => write!(f, "The reference is invalid."), | 
| 222 | 0 |             Error::NeedVersion(version) => write!( | 
| 223 | 0 |                 f, | 
| 224 | 0 |                 "A requested feature requires a DWARF version {}.", | 
| 225 | 0 |                 version | 
| 226 | 0 |             ), | 
| 227 |  |             Error::LineStringFormMismatch => { | 
| 228 | 0 |                 write!(f, "Strings in line number program have mismatched forms.") | 
| 229 |  |             } | 
| 230 | 0 |             Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."), | 
| 231 | 0 |             Error::IncompatibleLineProgramEncoding => write!( | 
| 232 | 0 |                 f, | 
| 233 | 0 |                 "The line number program encoding is incompatible with the unit encoding." | 
| 234 | 0 |             ), | 
| 235 | 0 |             Error::InvalidFrameCodeOffset(offset) => write!( | 
| 236 | 0 |                 f, | 
| 237 | 0 |                 "Could not encode code offset ({}) for a frame instruction.", | 
| 238 | 0 |                 offset, | 
| 239 | 0 |             ), | 
| 240 | 0 |             Error::InvalidFrameDataOffset(offset) => write!( | 
| 241 | 0 |                 f, | 
| 242 | 0 |                 "Could not encode data offset ({}) for a frame instruction.", | 
| 243 | 0 |                 offset, | 
| 244 | 0 |             ), | 
| 245 | 0 |             Error::UnsupportedPointerEncoding(eh_pe) => { | 
| 246 | 0 |                 write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe) | 
| 247 |  |             } | 
| 248 |  |             Error::UnsupportedCfiExpressionReference => { | 
| 249 | 0 |                 write!(f, "Unsupported reference in CFI expression.") | 
| 250 |  |             } | 
| 251 |  |             Error::UnsupportedExpressionForwardReference => { | 
| 252 | 0 |                 write!(f, "Unsupported forward reference in expression.") | 
| 253 |  |             } | 
| 254 |  |         } | 
| 255 | 0 |     } | 
| 256 |  | } | 
| 257 |  |  | 
| 258 |  | impl error::Error for Error {} | 
| 259 |  |  | 
| 260 |  | /// The result of a write. | 
| 261 |  | pub type Result<T> = result::Result<T, Error>; | 
| 262 |  |  | 
| 263 |  | /// An address. | 
| 264 |  | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 
| 265 |  | pub enum Address { | 
| 266 |  |     /// A fixed address that does not require relocation. | 
| 267 |  |     Constant(u64), | 
| 268 |  |     /// An address that is relative to a symbol which may be relocated. | 
| 269 |  |     Symbol { | 
| 270 |  |         /// The symbol that the address is relative to. | 
| 271 |  |         /// | 
| 272 |  |         /// The meaning of this value is decided by the writer, but | 
| 273 |  |         /// will typically be an index into a symbol table. | 
| 274 |  |         symbol: usize, | 
| 275 |  |         /// The offset of the address relative to the symbol. | 
| 276 |  |         /// | 
| 277 |  |         /// This will typically be used as the addend in a relocation. | 
| 278 |  |         addend: i64, | 
| 279 |  |     }, | 
| 280 |  | } | 
| 281 |  |  | 
| 282 |  | /// A reference to a `.debug_info` entry. | 
| 283 |  | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 
| 284 |  | pub enum Reference { | 
| 285 |  |     /// An external symbol. | 
| 286 |  |     /// | 
| 287 |  |     /// The meaning of this value is decided by the writer, but | 
| 288 |  |     /// will typically be an index into a symbol table. | 
| 289 |  |     Symbol(usize), | 
| 290 |  |     /// An entry in the same section. | 
| 291 |  |     /// | 
| 292 |  |     /// This only supports references in units that are emitted together. | 
| 293 |  |     Entry(UnitId, UnitEntryId), | 
| 294 |  | } | 
| 295 |  |  | 
| 296 |  | // This type is only used in debug assertions. | 
| 297 |  | #[cfg(not(debug_assertions))] | 
| 298 |  | type BaseId = (); | 
| 299 |  |  | 
| 300 |  | #[cfg(debug_assertions)] | 
| 301 |  | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 
| 302 |  | struct BaseId(usize); | 
| 303 |  |  | 
| 304 |  | #[cfg(debug_assertions)] | 
| 305 |  | impl Default for BaseId { | 
| 306 |  |     fn default() -> Self { | 
| 307 |  |         use std::sync::atomic; | 
| 308 |  |         static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0); | 
| 309 |  |         BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed)) | 
| 310 |  |     } | 
| 311 |  | } | 
| 312 |  |  | 
| 313 |  | #[cfg(feature = "read")] | 
| 314 |  | mod convert { | 
| 315 |  |     use super::*; | 
| 316 |  |     use crate::read; | 
| 317 |  |  | 
| 318 |  |     pub(crate) use super::unit::convert::*; | 
| 319 |  |  | 
| 320 |  |     /// An error that occurred when converting a read value into a write value. | 
| 321 |  |     #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 
| 322 |  |     pub enum ConvertError { | 
| 323 |  |         /// An error occurred when reading. | 
| 324 |  |         Read(read::Error), | 
| 325 |  |         /// Writing of this attribute value is not implemented yet. | 
| 326 |  |         UnsupportedAttributeValue, | 
| 327 |  |         /// This attribute value is an invalid name/form combination. | 
| 328 |  |         InvalidAttributeValue, | 
| 329 |  |         /// A `.debug_info` reference does not refer to a valid entry. | 
| 330 |  |         InvalidDebugInfoOffset, | 
| 331 |  |         /// An address could not be converted. | 
| 332 |  |         InvalidAddress, | 
| 333 |  |         /// Writing this line number instruction is not implemented yet. | 
| 334 |  |         UnsupportedLineInstruction, | 
| 335 |  |         /// Writing this form of line string is not implemented yet. | 
| 336 |  |         UnsupportedLineStringForm, | 
| 337 |  |         /// A `.debug_line` file index is invalid. | 
| 338 |  |         InvalidFileIndex, | 
| 339 |  |         /// A `.debug_line` directory index is invalid. | 
| 340 |  |         InvalidDirectoryIndex, | 
| 341 |  |         /// A `.debug_line` line base is invalid. | 
| 342 |  |         InvalidLineBase, | 
| 343 |  |         /// A `.debug_line` reference is invalid. | 
| 344 |  |         InvalidLineRef, | 
| 345 |  |         /// A `.debug_info` unit entry reference is invalid. | 
| 346 |  |         InvalidUnitRef, | 
| 347 |  |         /// A `.debug_info` reference is invalid. | 
| 348 |  |         InvalidDebugInfoRef, | 
| 349 |  |         /// Invalid relative address in a range list. | 
| 350 |  |         InvalidRangeRelativeAddress, | 
| 351 |  |         /// Writing this CFI instruction is not implemented yet. | 
| 352 |  |         UnsupportedCfiInstruction, | 
| 353 |  |         /// Writing indirect pointers is not implemented yet. | 
| 354 |  |         UnsupportedIndirectAddress, | 
| 355 |  |         /// Writing this expression operation is not implemented yet. | 
| 356 |  |         UnsupportedOperation, | 
| 357 |  |         /// Operation branch target is invalid. | 
| 358 |  |         InvalidBranchTarget, | 
| 359 |  |         /// Writing this unit type is not supported yet. | 
| 360 |  |         UnsupportedUnitType, | 
| 361 |  |     } | 
| 362 |  |  | 
| 363 |  |     impl fmt::Display for ConvertError { | 
| 364 | 0 |         fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { | 
| 365 | 0 |             use self::ConvertError::*; | 
| 366 | 0 |             match *self { | 
| 367 | 0 |                 Read(ref e) => e.fmt(f), | 
| 368 |  |                 UnsupportedAttributeValue => { | 
| 369 | 0 |                     write!(f, "Writing of this attribute value is not implemented yet.") | 
| 370 |  |                 } | 
| 371 | 0 |                 InvalidAttributeValue => write!( | 
| 372 | 0 |                     f, | 
| 373 | 0 |                     "This attribute value is an invalid name/form combination." | 
| 374 | 0 |                 ), | 
| 375 | 0 |                 InvalidDebugInfoOffset => write!( | 
| 376 | 0 |                     f, | 
| 377 | 0 |                     "A `.debug_info` reference does not refer to a valid entry." | 
| 378 | 0 |                 ), | 
| 379 | 0 |                 InvalidAddress => write!(f, "An address could not be converted."), | 
| 380 | 0 |                 UnsupportedLineInstruction => write!( | 
| 381 | 0 |                     f, | 
| 382 | 0 |                     "Writing this line number instruction is not implemented yet." | 
| 383 | 0 |                 ), | 
| 384 | 0 |                 UnsupportedLineStringForm => write!( | 
| 385 | 0 |                     f, | 
| 386 | 0 |                     "Writing this form of line string is not implemented yet." | 
| 387 | 0 |                 ), | 
| 388 | 0 |                 InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."), | 
| 389 | 0 |                 InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."), | 
| 390 | 0 |                 InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."), | 
| 391 | 0 |                 InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."), | 
| 392 | 0 |                 InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."), | 
| 393 | 0 |                 InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."), | 
| 394 |  |                 InvalidRangeRelativeAddress => { | 
| 395 | 0 |                     write!(f, "Invalid relative address in a range list.") | 
| 396 |  |                 } | 
| 397 |  |                 UnsupportedCfiInstruction => { | 
| 398 | 0 |                     write!(f, "Writing this CFI instruction is not implemented yet.") | 
| 399 |  |                 } | 
| 400 |  |                 UnsupportedIndirectAddress => { | 
| 401 | 0 |                     write!(f, "Writing indirect pointers is not implemented yet.") | 
| 402 |  |                 } | 
| 403 | 0 |                 UnsupportedOperation => write!( | 
| 404 | 0 |                     f, | 
| 405 | 0 |                     "Writing this expression operation is not implemented yet." | 
| 406 | 0 |                 ), | 
| 407 | 0 |                 InvalidBranchTarget => write!(f, "Operation branch target is invalid."), | 
| 408 | 0 |                 UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."), | 
| 409 |  |             } | 
| 410 | 0 |         } | 
| 411 |  |     } | 
| 412 |  |  | 
| 413 |  |     impl error::Error for ConvertError {} | 
| 414 |  |  | 
| 415 |  |     impl From<read::Error> for ConvertError { | 
| 416 | 0 |         fn from(e: read::Error) -> Self { | 
| 417 | 0 |             ConvertError::Read(e) | 
| 418 | 0 |         } | 
| 419 |  |     } | 
| 420 |  |  | 
| 421 |  |     /// The result of a conversion. | 
| 422 |  |     pub type ConvertResult<T> = result::Result<T, ConvertError>; | 
| 423 |  | } | 
| 424 |  | #[cfg(feature = "read")] | 
| 425 |  | pub use self::convert::*; |