silo:std.path

Source src/silo:std.path

1##! Path — platform-independent file-system path values and operations.
2##!
3##! Unix-only today: the `UnixPath` / `UnixSeg` variants are populated
4##! and `main-separator` returns `/`. The Windows variants are declared
5##! so the type shape matches the spec, but observing one at runtime
6##! panics; compile-time `@cfg` dispatch arrives with the Windows
7##! target.
8##!
9##! `Display` impls land alongside the format pipeline.
10
11:use
12  :open core AnyInt Bool Byte Codepoint Option None Some Result Ok Err Str U8 U16 Vec
13:end
14
15# si[impl stdlib.path.type+2]
16##(
17`Path` MUST be an internal union of OS-native byte representations. On
18Unix targets the `UnixPath` variant is populated with a sequence of
198-bit bytes; on Windows targets `WindowsPath` carries 16-bit code units.
20The concrete variant is selected per target at compile time. Paths are
21NOT guaranteed to be valid UTF-8.
22)#
23:union(pub) Path
24  | UnixPath (Vec U8)
25  | WindowsPath (Vec U16)
26:end
27
28# si[impl stdlib.path.segment]
29##(
30`PathSegment` is a narrow type representing a single path fragment in
31OS-native bytes. Mirrors `Path`'s variants.
32)#
33:union(pub) PathSegment
34  | UnixSeg (Vec U8)
35  | WindowsSeg (Vec U16)
36:end
37
38# si[impl stdlib.path.component]
39##(
40`Component` classifies the kinds of fragment encountered while walking
41a `Path`. Mirrors Rust's `std::path::Component` minus the Windows
42`Prefix` variant (Silo is Unix-only until the Windows target lands).
43
44Variants:
45  - `Normal PathSegment` — a regular path segment in OS-native bytes.
46  - `RootDir` — the leading `/` of an absolute path.
47  - `CurDir` — a `.` fragment.
48  - `ParentDir` — a `..` fragment.
49)#
50:union(pub) Component
51  | Normal PathSegment
52  | RootDir
53  | CurDir
54  | ParentDir
55:end
56
57:impl Path
58  # si[impl stdlib.path.from-str+1]
59  ## `.from-str` — parse a `Str` into a `Path`. Leading `/` marks
60  ## absolute; consecutive `/` collapse; trailing `/` is dropped.
61  ## Qualified dispatch: `"/home/user" (Path .from-str)`.
62  .from-str ( Str -> Path )
63    path-from-str-intrinsic ;
64
65  # si[impl stdlib.path.to-str+2]
66  ## `.to-str` — render a `Path` back to a `Str`. Returns `Err` when
67  ## the underlying bytes are not valid UTF-8.
68  .to-str ( Path -> (Result Str Str) )
69    path-to-str-intrinsic ;
70
71  # si[impl stdlib.path.to-string-lossy+1]
72  ## `.to-string-lossy` — always-successful Str rendering; invalid
73  ## UTF-8 is replaced with U+FFFD.
74  .to-string-lossy ( Path -> Str )
75    path-to-string-lossy-intrinsic ;
76
77  # si[impl stdlib.path.segments]
78  ## `.segments` — the sequence of `PathSegment` values after parsing,
79  ## excluding any leading root marker.
80  .segments ( Path -> (Vec PathSegment) )
81    path-segments-intrinsic ;
82
83  # si[impl stdlib.path.file-name+1]
84  ## `.file-name` — last segment as `(Option PathSegment)`; `None` if
85  ## the path has no segments.
86  .file-name ( Path -> (Option PathSegment) )
87    path-file-name-intrinsic ;
88
89  # si[impl stdlib.path.extension+1]
90  ## `.extension` — file extension (portion of last segment after the
91  ## final `.`). `None` if no `.`, `.` is first char, or no segments.
92  .extension ( Path -> (Option PathSegment) )
93    path-extension-intrinsic ;
94
95  # si[impl stdlib.path.stem+1]
96  ## `.stem` — last segment with its extension stripped. `None` iff the
97  ## path has no segments.
98  .stem ( Path -> (Option PathSegment) )
99    path-stem-intrinsic ;
100
101  # si[impl stdlib.path.parent+1]
102  ## `.parent` — path with last segment removed, or `None` if already at
103  ## root. Single-segment paths yield `/` (absolute) or `.` (relative).
104  .parent ( Path -> (Option Path) )
105    path-parent-intrinsic ;
106
107  # si[impl stdlib.path.join+1]
108  ## `.join` — append a segment string. The string MUST NOT contain `/`.
109  .join ( Path Str -> Path )
110    path-join-intrinsic ;
111
112  # si[impl stdlib.path.is-absolute+1]
113  ## `.is-absolute` — true iff the path starts with `/`.
114  .is-absolute ( Path -> Bool )
115    path-is-absolute-intrinsic ;
116
117  # si[impl stdlib.path.is-relative+1]
118  ## `.is-relative` — `true` iff the path does not start with `/`.
119  .is-relative ( Path -> Bool )
120    path-is-relative-intrinsic ;
121
122  # si[impl stdlib.path.components+1]
123  ## `.components` — decompose the path into its left-to-right sequence
124  ## of `Component` values. `RootDir` appears first (and only first) when
125  ## the path is absolute. `.` / `..` fragments surface as `CurDir` /
126  ## `ParentDir` and are NOT resolved (that is `.canonicalize`'s job).
127  .components ( Path -> (Vec Component) )
128    path-components-intrinsic ;
129:end
130
131# si[impl stdlib.path.segment+1]
132:impl PathSegment
133  ## `.to-str` — decode as UTF-8; `Err` on invalid sequences.
134  .to-str ( PathSegment -> (Result Str Str) )
135    pathseg-to-str-intrinsic ;
136  ## `.to-string-lossy` — always-successful Str rendering.
137  .to-string-lossy ( PathSegment -> Str )
138    pathseg-to-string-lossy-intrinsic ;
139:end
140
141# si[impl stdlib.path.main-separator]
142##(
143`main-separator` — the host target's primary path separator, as a
144`Codepoint`. On Unix the value is `/` (U+002F); on Windows it would be
145`\` (U+005C). Silo is currently Unix-only, so this always returns `/`.
146
147Naming: the spec's Rust-style example uses the identifier
148`MAIN_SEPARATOR`; Silo's current grammar only permits lower-case
149identifiers as `:fn` names, so we expose this as `main-separator`.
150Once Silo grows an uppercase-const syntax (and `@cfg` dispatch for
151Windows), both changes will land together.
152)#
153:fn(pub) main-separator ( -> Codepoint )
154  path-main-separator-intrinsic
155:end