rust
42 lines · 9 steps
Parsing INI files in Rust
A streaming parser that reads an INI file line by line into a nested map of sections and key-value pairs.
Explained by
highlit
1use std::collections::HashMap;
2use std::fs::File;
3use std::io::{self, BufRead, BufReader};
4use std::path::Path;
5
6type Ini = HashMap<String, HashMap<String, String>>;
7
8pub fn parse_ini<P: AsRef<Path>>(path: P) -> io::Result<Ini> {
9 let reader = BufReader::new(File::open(path)?);
10 let mut sections: Ini = HashMap::new();
11 let mut current = String::new();
12 sections.entry(current.clone()).or_default();
13
14 for line in reader.lines() {
15 let line = line?;
16 let trimmed = line.trim();
17
18 if trimmed.is_empty() || trimmed.starts_with('#') || trimmed.starts_with(';') {
19 continue;
20 }
21
22 if let Some(name) = trimmed.strip_prefix('[').and_then(|s| s.strip_suffix(']')) {
23 current = name.trim().to_string();
24 sections.entry(current.clone()).or_default();
25 continue;
26 }
27
28 if let Some((key, value)) = trimmed.split_once('=') {
29 let value = value.trim();
30 let value = value
31 .strip_prefix('"')
32 .and_then(|v| v.strip_suffix('"'))
33 .unwrap_or(value);
34 sections
35 .get_mut(¤t)
36 .unwrap()
37 .insert(key.trim().to_string(), value.to_string());
38 }
39 }
40
41 Ok(sections)
42}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Tracking a mutable current-section string lets a flat line loop build a nested structure.
- 2The ? operator threads I/O failures out cleanly so the parser body stays focused on parsing.
- 3or_default and get_mut give ergonomic insert-or-fetch access to nested HashMaps without manual existence checks.
Related explainers
ruby
class Order class InvalidTransition < StandardError; end TRANSITIONS = {
A state machine for order transitions in Ruby
state-machine
data-driven
error-handling
Intermediate
8 steps
rust
use std::cmp::Ordering; pub struct PrefixIndex { entries: Vec<String>,
Prefix search with binary partitioning in Rust
binary-search
sorting
case-insensitive
Intermediate
7 steps
rust
use std::cmp::Ordering; use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Eq)]
Parsing and ordering semantic versions in Rust
parsing
trait-implementation
ordering
Intermediate
8 steps
javascript
'use client'; import { useEffect } from 'react'; import * as Sentry from '@sentry/nextjs';
How a Next.js error boundary recovers
error-boundary
error-handling
observability
Intermediate
8 steps
ruby
class Registration < ApplicationRecord belongs_to :event validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
Validating registrations in Rails
validations
i18n
error-handling
Intermediate
8 steps
ruby
class ApacheLogParser LINE_PATTERN = /\A(?<ip>\S+)\s\S+\s\S+\s\[(?<time>[^\]]+)\]\s"(?<method>[A-Z]+)\s(?<path>\S+)\s(?<protocol>[^"]+)"\s(?<status>\d{3})\s(?<bytes>\d+|-)/ TIME_FORMAT = "%d/%b/%Y:%H:%M:%S %z"
Parsing Apache logs with named captures
regex
named-captures
parsing
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/parsing-ini-files-in-rust-explained-rust-2e95/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.