···11+# Portability Plan: Linux and BSD
22+33+This document proposes how to evolve this downloader from Linux-first to a portable Unix implementation that supports Linux and BSDs without changing the core HTTP flow.
44+55+Current implementation references:
66+77+- [`/src/main.rs`](/src/main.rs)
88+- [`/Cargo.toml`](/Cargo.toml)
99+- [`/README.md`](/README.md)
1010+1111+## Goals
1212+1313+- Keep downloader logic backend-agnostic (`reqwless` + `embedded-nal-async` traits).
1414+- Support multiple platform backends: `posix-libc` and `rustix`.
1515+- Keep feature gating explicit and mutually exclusive where needed.
1616+- Preserve low-allocation behavior and fixed-buffer streaming.
1717+1818+## Backend Strategy
1919+2020+We should support two backends with a single shared app layer.
2121+2222+### Backend 1: `posix-libc`
2323+2424+- Best compatibility baseline for Linux + BSDs.
2525+- Straightforward access to `socket`, `connect`, `read/write`, `close`, `getaddrinfo`.
2626+- Good default while portability is the top priority.
2727+2828+### Backend 2: `rustix`
2929+3030+- Safer syscall wrappers and stronger typing.
3131+- Better long-term ergonomics around low-level I/O.
3232+- DNS coverage is not identical to libc flows, so resolver strategy must be deliberate.
3333+3434+## DNS and Address Conversion Are Separate Problems
3535+3636+We should treat these as separate design axes.
3737+3838+### Problem A: DNS Resolution
3939+4040+Options:
4141+4242+1. `dns-getaddrinfo` (portable baseline)
4343+ - Use libc `getaddrinfo` style resolution.
4444+ - Works well for Linux + BSD.
4545+2. `dns-ip-only` (minimal fallback)
4646+ - Accept only literal IP hosts; reject names.
4747+ - Useful for strict/minimal builds.
4848+3. `dns-custom` (future)
4949+ - Dedicated resolver implementation.
5050+ - More control, higher complexity.
5151+5252+Recommendation: start with `dns-getaddrinfo` for the portable baseline and keep `dns-ip-only` as a tiny fallback mode.
5353+5454+### Problem B: Address Conversion
5555+5656+This means converting `core::net::SocketAddr` into backend-specific connect input.
5757+5858+Options:
5959+6060+1. Backend-owned conversion (recommended)
6161+ - `platform/posix_libc/addr.rs` owns libc sockaddr packing.
6262+ - `platform/rustix/addr.rs` owns rustix address adaptation.
6363+ - Keeps unsafe and ABI assumptions local to each backend.
6464+2. Shared conversion module
6565+ - One common converter to a raw sockaddr representation.
6666+ - Less duplication, but can over-couple backends to one memory layout contract.
6767+6868+Recommendation: start backend-owned. If patterns converge, extract shared pieces later.
6969+7070+## Proposed Structure
7171+7272+Use domain-grouped layout (not flat):
7373+7474+```text
7575+src/
7676+ app/
7777+ main.rs
7878+ download.rs
7979+ net/
8080+ mod.rs
8181+ traits.rs
8282+ errors.rs
8383+ platform/
8484+ mod.rs
8585+ posix_libc/
8686+ mod.rs
8787+ tcp.rs
8888+ dns.rs
8989+ addr.rs
9090+ errno.rs
9191+ rustix/
9292+ mod.rs
9393+ tcp.rs
9494+ dns.rs
9595+ addr.rs
9696+ runtime/
9797+ executor.rs
9898+ fd_io.rs
9999+```
100100+101101+- `app/`: URL handling, request flow, stdout streaming.
102102+- `net/`: shared adapter interfaces and error mapping.
103103+- `platform/`: backend-specific networking + DNS + address conversion.
104104+- `runtime/`: executor and FD utilities.
105105+106106+## Feature Model
107107+108108+Suggested Cargo features:
109109+110110+- `backend-posix-libc` (default)
111111+- `backend-rustix`
112112+- `dns-getaddrinfo` (default with `backend-posix-libc`)
113113+- `dns-ip-only`
114114+115115+Build rules:
116116+117117+- Exactly one backend must be enabled.
118118+- Exactly one DNS mode must be enabled.
119119+- Enforce at compile time with `compile_error!` guards.
120120+121121+## Integration Shape
122122+123123+```mermaid
124124+flowchart LR
125125+ CLI[app/main] --> DL[app/download]
126126+ DL --> NAL[embedded-nal-async traits]
127127+ NAL --> SEL{backend feature}
128128+ SEL --> LIBC[platform/posix_libc]
129129+ SEL --> RUSTIX[platform/rustix]
130130+ LIBC --> DNS{dns mode}
131131+ RUSTIX --> DNS
132132+ DNS --> OUT[stdout stream]
133133+```
134134+135135+## Practical Notes
136136+137137+- Keep all `unsafe` inside backend modules only.
138138+- Keep error translation close to syscall sites.
139139+- Avoid backend-specific types leaking into `app/`.
140140+- Preserve fixed-size buffers and streaming body reads.
141141+142142+## Proposed Initial Default
143143+144144+- Backend: `backend-posix-libc`
145145+- DNS: `dns-getaddrinfo`
146146+- HTTPS: optional feature (already added)
147147+148148+This gives the best near-term Linux/BSD portability while leaving room to add `rustix` as a first-class backend without redesigning the app layer.