Skip to content

Commit

Permalink
WIP: C# and Python implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
Apprentice-Alchemist committed Jun 18, 2024
1 parent c954924 commit 533d2c2
Show file tree
Hide file tree
Showing 15 changed files with 417 additions and 88 deletions.
118 changes: 64 additions & 54 deletions std/cs/_std/sys/fs/File.hx
Original file line number Diff line number Diff line change
@@ -1,96 +1,106 @@
package sys.fs;

import cs.system.io.SeekOrigin;
import cs.system.io.FileStream;
import cs.system.io.FileAccess;
import cs.system.io.FileMode;
import haxe.Int64;
import cs.system.io.File as CsFile;
import haxe.time.SystemTime;
import haxe.io.Bytes;
import haxe.Result;
import sys.fs.Metadata;
import sys.Error;
import sys.fs.Path;
import sys.fs.SeekPos;

import cs.system.io.FileMode;
import cs.system.io.File as NativeFile;

enum SeekPos {
SeekBegin(offset:haxe.Int64);
SeekCurrent(offset:haxe.Int64);
SeekEnd(offset:haxe.Int64);
}

@:coreApi
class File {
/**
Opens the file in read-only mode.
**/
static function open(p:Path):Result<File, Error> {
try {
cs.system.io.File.Open(p.toString(), FileMode.Open);

}
return Err(Unsupported);
public static function open(p:Path, ?options:OpenOptions):File {
options ??= {read: true};
var mode:FileMode = if (options.append) Append else if (options.truncate) Truncate else if (options.create_new) CreateNew else if (options.create)
Create else Open;
var access:FileAccess = if (options.read && options.write) ReadWrite else if (options.write) Write else if (options.read) Read else
throw "can never read nor write to file";
final stream = CsFile.Open(p.toString(), mode, access);
return new File(p.toString(), stream);
}

/**
Opens the file in write-only mode, creating it if needed.
**/
static function create(p:Path):Result<File, Error> {
return Err(Unsupported);
public static function create(p:Path):File {
return open(p, {write: true});
}

/**
Opens the file in write-only mode, always creating a new one.
Returns an error if the file already exists.
**/
static function createNew(p:Path):Result<File, Error> {
return Err(Unsupported);
public static function createNew(p:Path):File {
return open(p, {write: true, create_new: true});
}

static function readAll(p:Path):Result<Bytes, Error> {
return Err(Unsupported);
public static function readAll(p:Path):Bytes {
return Bytes.ofData(CsFile.ReadAllBytes(p.toString()));
}

static function writeAll(p:Path, b:Bytes):Result<Void /* TODO */, Error> {
return Err(Unsupported);
public static function writeAll(p:Path, b:Bytes):Void {
CsFile.WriteAllBytes(p.toString(), b.getData());
}

static function appendAll(p:Path, b:Bytes):Result<Void /* TODO */, Error> {
return Err(Unsupported);
public static function appendAll(p:Path, b:Bytes):Void {
final file = open(p, {append: true, write: true});
file.write(b, 0, b.length);
file.close();
}

final path:String;
final stream:FileStream;

function new(file:FileStream) {
this.stream = file;
function new(path:String, stream:FileStream) {
this.path = path;
this.stream = stream;
}

function syncAll():Result<Void /* TODO */, Error> {
public function syncAll():Void {
stream.Flush();
return Ok((null:Void));
}

function syncData():Result<Void /* TODO */, Error> {
return syncAll();
public function syncData():Void {
stream.Flush();
}

function metadata():Result<Metadata, Error> {
return Err(Unsupported);
public function metadata():Metadata {
return new Metadata(path, true);
}

function setPermissions(perm:Permissions):Result<Void /* TODO */, Error> {
return Err(Unsupported);
public function setPermissions(perm:Permissions):Void {
throw new haxe.exceptions.NotImplementedException();
}

// TODO: technically these should all use a UInt64 type

function read(bytes:haxe.io.Bytes, bufferOffset:Int, bufferLength:Int):Result<haxe.Int64, Error> {
return Err(Unsupported);
public function read(bytes:haxe.io.Bytes, bufferOffset:Int, bufferLength:Int):Int {
return stream.Read(bytes.getData(), bufferOffset, bufferLength);
}

function write(bytes:haxe.io.Bytes, bufferOffset:Int, bufferLength:Int):Result<haxe.Int64, Error> {
return Err(Unsupported);
public function write(bytes:haxe.io.Bytes, bufferOffset:Int, bufferLength:Int):Int {
var prevPos = stream.Position;
stream.Write(bytes.getData(), bufferOffset, bufferLength);
return (cast stream.Position - prevPos:Int);
}

function seek(pos:SeekPos):Result<haxe.Int64, Error> {
return Err(Unsupported);
public function seek(pos:SeekPos):Int64 {
var origin:SeekOrigin;
var offset:cs.StdTypes.Int64;
switch pos {
case SeekBegin(_offset):
offset = _offset;
origin = Begin;
case SeekCurrent(_offset):
offset = _offset;
origin = Current;
case SeekEnd(_offset):
offset = _offset;
origin = End;
}

return stream.Seek(offset, origin);
}

function close():Void {}
public function close():Void {
stream.Close();
}
}
57 changes: 45 additions & 12 deletions std/cs/_std/sys/fs/Fs.hx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,53 @@ package sys.fs;

import haxe.Result;
import sys.fs.Metadata;
import cs.system.io.File as CsFile;

class Fs {
static function metadata(path:Path):Metadata {
return new Metadata(path.toString(), true);
}

extern class Fs {
static function metadata(path:Path):Result<Metadata, Error>;
/**
Returns the metadata for `path` without following symlinks.
**/
static function symlinkMetadata(path:Path):Result<Metadata, Error>;
static function setPermissions(path:Path, perm:Permissions):Result<Void /* TODO */, Error>;
static function copy(from:Path, to:Path):Result<Void /* TODO */, Error>;
static function rename(from:Path, to:Path):Result<Void /* TODO */, Error>;
static function readDir(path:Path):Result<Iterator<Result<Path, Error>>, Error>;
static function createDir(path:Path):Result<Void /* TODO */, Error>;
static function createDirRec(path:Path):Result<Void /* TODO */, Error>;
static function removeDir(path:Path):Result<Void /* TODO */, Error>;
static function removeDirRec(path:Path):Result<Void /* TODO */, Error>;
static function removeFile(path:Path):Result<Void /* TODO */, Error>;
static function symlinkMetadata(path:Path):Metadata {
throw new haxe.exceptions.NotImplementedException();
}

static function setPermissions(path:Path, perm:Permissions):Void {
throw new haxe.exceptions.NotImplementedException();
}

static function copy(from:Path, to:Path):Void {
throw new haxe.exceptions.NotImplementedException();
}

static function rename(from:Path, to:Path):Void {
throw new haxe.exceptions.NotImplementedException();
}

static function readDir(path:Path):Iterator<DirEntry> {
throw new haxe.exceptions.NotImplementedException();
}

static function createDir(path:Path):Void {
throw new haxe.exceptions.NotImplementedException();
}

static function createDirRec(path:Path):Void {
throw new haxe.exceptions.NotImplementedException();
}

static function removeDir(path:Path):Void {
throw new haxe.exceptions.NotImplementedException();
}

static function removeDirRec(path:Path):Void {
throw new haxe.exceptions.NotImplementedException();
}

static function removeFile(path:Path):Void {
throw new haxe.exceptions.NotImplementedException();
}
}
89 changes: 74 additions & 15 deletions std/cs/_std/sys/fs/Metadata.hx
Original file line number Diff line number Diff line change
@@ -1,21 +1,80 @@
package sys.fs;

import cs.system.DateTime;
import cs.system.io.FileInfo;
import cs.system.io.FileAttributes;
import haxe.Result;
import cs.system.io.File as CsFile;

extern class Metadata {
function isDir():Bool;
function isFile():Bool;
function isSymlink():Bool;
function size():haxe.Int64;
function permissions():Permissions;
function modified():Null<haxe.time.SystemTime>;
function accessed():Null<haxe.time.SystemTime>;
function created():Null<haxe.time.SystemTime>;
class Metadata {
final path:String;
final followSymlinks:Bool;
final attributes:FileAttributes;
final fileInfo:FileInfo;

@:allow(sys.fs)
function new(path:String, followSymlinks:Bool) {
this.path = path;
this.followSymlinks = followSymlinks;
this.attributes = CsFile.GetAttributes(this.path);
fileInfo = new FileInfo(path);
#if (cs_ver>=6)
if(followSymlinks && fileInfo.LinkTarget != null) {
fileInfo = fileInfo.ResolveTarget(true);
}
#end
}

private inline function contains(attr:FileAttributes):Bool {
return untyped (attributes & attr) == attr;
}

function isDir():Bool {
return contains(Directory);
}

function isFile():Bool {
return !isDir() && !isSymlink();
}

function isSymlink():Bool {
#if (cs_ver >= 6)
return fileInfo.LinkTarget != null
#else
return false;
#end
}

function size():haxe.Int64 {
return fileInfo.Length;
}

function permissions():Permissions {
throw new haxe.exceptions.NotImplementedException();
}

function modified():Null<haxe.time.SystemTime> {
// return fileInfo.LastWriteTime;
throw new haxe.exceptions.NotImplementedException();
}

function accessed():Null<haxe.time.SystemTime> {
throw new haxe.exceptions.NotImplementedException();
}

function created():Null<haxe.time.SystemTime> {
throw new haxe.exceptions.NotImplementedException();
}
}

private function SystemTimeFromDateTime(date:DateTime) {
// DateTime.UnixEpoch;
// return new haxe.time.SystemTime(date);
}

extern class Permissions {
/**
Note that this does not affect the file, use `Fs.setPermissions`.
**/
var readonly(get, set):Bool;
}
// extern class Permissions {
// /**
// Note that this does not affect the file, use `Fs.setPermissions`.
// **/
// var readonly(get, set):Bool;
// }
2 changes: 2 additions & 0 deletions std/java/_std/sys/fs/File.hx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class File {
if(options.write) opts.add(WRITE);
if(options.create) opts.add(CREATE);
if(options.create_new) opts.add(CREATE_NEW);
if(options.append) opts.add(APPEND);
if(options.truncate) opts.add(TRUNCATE_EXISTING);
final path = java.nio.file.Paths.get(p.toString());
return try new File(path, FileChannel.open(path, opts)) catch (e) {
throw e;
Expand Down
6 changes: 6 additions & 0 deletions std/python/Memoryview.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package python;

@:native("memoryview")
extern class Memoryview implements ArrayAccess<Int> {
function new(b:Bytearray):Void;
}
6 changes: 6 additions & 0 deletions std/python/_std/sys/fs/DirEntry.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package sys.fs;

extern class DirEntry {
function path():Path;
function metadata():Metadata;
}
Loading

0 comments on commit 533d2c2

Please sign in to comment.