aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-11-26 15:04:55 +0000
committerGitHub <noreply@github.com>2025-11-26 15:04:55 +0000
commitf48e87d77d1376f03cf53afbc51b695698d6e5a7 (patch)
tree01688dc28a690a16a2f5bf8d18236b65cf655021 /core
parent5caaefddb1551670d6f4e58cb53e29fec6ae4ccf (diff)
parente53bc165ae29d83e55645d1b7af356063ff0f2c9 (diff)
Merge pull request #5930 from odin-lang/bill/os2-file-stream
`os2.File_Stream`
Diffstat (limited to 'core')
-rw-r--r--core/os/os2/file.odin61
-rw-r--r--core/os/os2/file_linux.odin65
-rw-r--r--core/os/os2/file_posix.odin13
-rw-r--r--core/os/os2/file_stream.odin65
-rw-r--r--core/os/os2/file_windows.odin32
-rw-r--r--core/os/os2/stat.odin7
6 files changed, 162 insertions, 81 deletions
diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin
index 85ebfcece..9e7788c31 100644
--- a/core/os/os2/file.odin
+++ b/core/os/os2/file.odin
@@ -22,8 +22,7 @@ import "base:runtime"
*/
File :: struct {
impl: rawptr,
- stream: io.Stream,
- fstat: Fstat_Callback,
+ stream: File_Stream,
}
/*
@@ -218,7 +217,11 @@ name :: proc(f: ^File) -> string {
*/
close :: proc(f: ^File) -> Error {
if f != nil {
- return io.close(f.stream)
+ if f.stream.procedure == nil {
+ return .Unsupported
+ }
+ _, err := f.stream.procedure(f, .Close, nil, 0, nil, runtime.nil_allocator())
+ return err
}
return nil
}
@@ -235,7 +238,10 @@ close :: proc(f: ^File) -> Error {
*/
seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) {
if f != nil {
- return io.seek(f.stream, offset, whence)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ return f.stream.procedure(f, .Seek, nil, offset, whence, runtime.nil_allocator())
}
return 0, .Invalid_File
}
@@ -247,7 +253,12 @@ seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Err
*/
read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
if f != nil {
- return io.read(f.stream, p)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Read, p, 0, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -260,7 +271,12 @@ read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
*/
read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
if f != nil {
- return io.read_at(f.stream, p, offset)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Read_At, p, offset, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -272,7 +288,12 @@ read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
*/
write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
if f != nil {
- return io.write(f.stream, p)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Write, p, 0, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -284,7 +305,12 @@ write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
*/
write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
if f != nil {
- return io.write_at(f.stream, p, offset)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Write_At, p, offset, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -294,7 +320,18 @@ write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
*/
file_size :: proc(f: ^File) -> (n: i64, err: Error) {
if f != nil {
- return io.size(f.stream)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n, err = f.stream.procedure(f, .Size, nil, 0, nil, runtime.nil_allocator())
+ if err == .Unsupported {
+ n = 0
+ curr := seek(f, 0, .Current) or_return
+ end := seek(f, 0, .End) or_return
+ seek(f, curr, .Start) or_return
+ n = end
+ }
+ return
}
return 0, .Invalid_File
}
@@ -304,7 +341,11 @@ file_size :: proc(f: ^File) -> (n: i64, err: Error) {
*/
flush :: proc(f: ^File) -> Error {
if f != nil {
- return io.flush(f.stream)
+ if f.stream.procedure == nil {
+ return .Unsupported
+ }
+ _, err := f.stream.procedure(f, .Flush, nil, 0, nil, runtime.nil_allocator())
+ return err
}
return nil
}
diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin
index 6d66ffd75..fb25ca411 100644
--- a/core/os/os2/file_linux.odin
+++ b/core/os/os2/file_linux.odin
@@ -29,19 +29,16 @@ _stdin := File{
stream = {
procedure = _file_stream_proc,
},
- fstat = _fstat,
}
_stdout := File{
stream = {
procedure = _file_stream_proc,
},
- fstat = _fstat,
}
_stderr := File{
stream = {
procedure = _file_stream_proc,
},
- fstat = _fstat,
}
@init
@@ -55,7 +52,6 @@ _standard_stream_init :: proc "contextless" () {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -109,7 +105,6 @@ _new_file :: proc(fd: uintptr, _: string, allocator: runtime.Allocator) -> (f: ^
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file, nil
}
@@ -476,88 +471,76 @@ _read_entire_pseudo_file_cstring :: proc(name: cstring, allocator: runtime.Alloc
}
@(private="package")
-_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
- ferr: Error
switch mode {
case .Read:
- n, ferr = _read(f, p)
- err = error_to_io_error(ferr)
+ n, err = _read(f, p)
return
case .Read_At:
- n, ferr = _read_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _read_at(f, p, offset)
return
case .Write:
- n, ferr = _write(f, p)
- err = error_to_io_error(ferr)
+ n, err = _write(f, p)
return
case .Write_At:
- n, ferr = _write_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _write_at(f, p, offset)
return
case .Seek:
- n, ferr = _seek(f, offset, whence)
- err = error_to_io_error(ferr)
+ n, err = _seek(f, offset, whence)
return
case .Size:
- n, ferr = _file_size(f)
- err = error_to_io_error(ferr)
+ n, err = _file_size(f)
return
case .Flush:
- ferr = _flush(f)
- err = error_to_io_error(ferr)
+ err = _flush(f)
return
case .Close, .Destroy:
- ferr = _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
}
return 0, .Unsupported
}
@(private="package")
-_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
- ferr: Error
switch mode {
case .Read:
- n, ferr = _read(f, p)
- err = error_to_io_error(ferr)
+ n, err = _read(f, p)
return
case .Read_At:
- n, ferr = _read_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _read_at(f, p, offset)
return
case .Write:
- n, ferr = _write(f, p)
- err = error_to_io_error(ferr)
+ n, err = _write(f, p)
return
case .Write_At:
- n, ferr = _write_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _write_at(f, p, offset)
return
case .Seek:
- n, ferr = _seek(f, offset, whence)
- err = error_to_io_error(ferr)
+ n, err = _seek(f, offset, whence)
return
case .Size:
- n, ferr = _file_size(f)
- err = error_to_io_error(ferr)
+ n, err = _file_size(f)
return
case .Flush:
- ferr = _flush(f)
- err = error_to_io_error(ferr)
+ err = _flush(f)
return
case .Close, .Destroy:
- ferr = _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
}
return 0, .Unsupported
}
diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin
index f445cb5f4..874ec7c7d 100644
--- a/core/os/os2/file_posix.odin
+++ b/core/os/os2/file_posix.odin
@@ -36,7 +36,6 @@ init_std_files :: proc "contextless" () {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -110,7 +109,6 @@ __new_file :: proc(handle: posix.FD, allocator: runtime.Allocator) -> ^File {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -371,7 +369,7 @@ _exists :: proc(path: string) -> bool {
return posix.access(cpath) == .OK
}
-_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
fd := f.fd
@@ -489,18 +487,19 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
return
case .Flush:
- ferr := _sync(&f.file)
- err = error_to_io_error(ferr)
+ err = _sync(&f.file)
return
case .Close, .Destroy:
- ferr := _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
case:
return 0, .Unsupported
}
diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin
index e1c29a792..af6e50921 100644
--- a/core/os/os2/file_stream.odin
+++ b/core/os/os2/file_stream.odin
@@ -1,12 +1,50 @@
package os2
+import "base:intrinsics"
+import "base:runtime"
import "core:io"
+// A subset of the io.Stream_Mode with added File specific modes
+File_Stream_Mode :: enum {
+ Close,
+ Flush,
+ Read,
+ Read_At,
+ Write,
+ Write_At,
+ Seek,
+ Size,
+ Destroy,
+ Query, // query what modes are available on `io.Stream`
+
+ Fstat, // File specific (not available on io.Stream)
+}
+#assert(intrinsics.type_is_superset_of(File_Stream_Mode, io.Stream_Mode))
+
+// Superset interface of io.Stream_Proc with the added `runtime.Allocator` parameter needed for the Fstat mode
+File_Stream_Proc :: #type proc(
+ stream_data: rawptr,
+ mode: File_Stream_Mode,
+ p: []byte,
+ offset: i64,
+ whence: io.Seek_From,
+ allocator: runtime.Allocator,
+) -> (n: i64, err: Error)
+
+File_Stream :: struct {
+ procedure: File_Stream_Proc,
+ data: rawptr,
+}
+
+
// Converts a file `f` into an `io.Stream`
to_stream :: proc(f: ^File) -> (s: io.Stream) {
if f != nil {
assert(f.stream.procedure != nil)
- s = f.stream
+ s = {
+ file_io_stream_proc,
+ f,
+ }
}
return
}
@@ -24,3 +62,28 @@ to_writer :: to_stream
even if it has no logical difference.
*/
to_reader :: to_stream
+
+
+@(private="package")
+file_io_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+ f := (^File)(stream_data)
+
+ file_stream_mode := transmute(File_Stream_Mode)mode
+
+ ferr: Error
+ n, ferr = f.stream.procedure(f, file_stream_mode, p, offset, whence, runtime.nil_allocator())
+ err = error_to_io_error(ferr)
+ return
+}
+
+@(private="package")
+file_stream_fstat_utility :: proc(f: ^File_Impl, p: []byte, allocator: runtime.Allocator) -> (err: Error) {
+ fi: File_Info
+ if len(p) >= size_of(fi) {
+ fi, err = _fstat(&f.file, allocator)
+ runtime.mem_copy_non_overlapping(raw_data(p), &fi, size_of(fi))
+ } else {
+ err = .Short_Buffer
+ }
+ return
+} \ No newline at end of file
diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin
index 03fbc596e..0d2f28642 100644
--- a/core/os/os2/file_windows.odin
+++ b/core/os/os2/file_windows.odin
@@ -65,7 +65,6 @@ init_std_files :: proc "contextless" () {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -185,7 +184,6 @@ _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file, nil
}
@@ -827,44 +825,38 @@ _exists :: proc(path: string) -> bool {
}
@(private="package")
-_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
- ferr: Error
switch mode {
case .Read:
- n, ferr = _read(f, p)
- err = error_to_io_error(ferr)
+ n, err = _read(f, p)
return
case .Read_At:
- n, ferr = _read_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _read_at(f, p, offset)
return
case .Write:
- n, ferr = _write(f, p)
- err = error_to_io_error(ferr)
+ n, err = _write(f, p)
return
case .Write_At:
- n, ferr = _write_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _write_at(f, p, offset)
return
case .Seek:
- n, ferr = _seek(f, offset, whence)
- err = error_to_io_error(ferr)
+ n, err = _seek(f, offset, whence)
return
case .Size:
- n, ferr = _file_size(f)
- err = error_to_io_error(ferr)
+ n, err = _file_size(f)
return
case .Flush:
- ferr = _flush(f)
- err = error_to_io_error(ferr)
+ err = _flush(f)
return
case .Close, .Destroy:
- ferr = _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
}
return 0, .Unsupported
}
diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin
index f87afc4c9..58df45754 100644
--- a/core/os/os2/stat.odin
+++ b/core/os/os2/stat.odin
@@ -46,8 +46,11 @@ file_info_delete :: proc(fi: File_Info, allocator: runtime.Allocator) {
fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
if f == nil {
return {}, nil
- } else if f.fstat != nil {
- return f->fstat(allocator)
+ } else if f.stream.procedure != nil {
+ fi: File_Info
+ data := ([^]byte)(&fi)[:size_of(fi)]
+ _, err := f.stream.procedure(f, .Fstat, data, 0, nil, allocator)
+ return fi, err
}
return {}, .Invalid_Callback
}