const std = @import("std"); const bun = @import("root").bun; const uv = bun.windows.libuv; const log = bun.Output.scoped(.PipeSource, false); pub const Source = union(enum) { pipe: *Pipe, tty: *Tty, file: *File, const Pipe = uv.Pipe; const Tty = uv.uv_tty_t; const File = struct { fs: uv.fs_t, iov: uv.uv_buf_t, file: uv.uv_file, }; pub fn getHandle(this: Source) *uv.Handle { switch (this) { .pipe => return @ptrCast(this.pipe), .tty => return @ptrCast(this.tty), .file => unreachable, } } pub fn toStream(this: Source) *uv.uv_stream_t { switch (this) { .pipe => return @ptrCast(this.pipe), .tty => return @ptrCast(this.tty), .file => unreachable, } } pub fn getFd(this: Source) bun.FileDescriptor { switch (this) { .pipe => return this.pipe.fd(), .tty => return this.tty.fd(), .file => return bun.FDImpl.fromUV(this.file.file).encode(), } } pub fn setData(this: Source, data: ?*anyopaque) void { switch (this) { .pipe => this.pipe.data = data, .tty => this.tty.data = data, .file => this.file.fs.data = data, } } pub fn getData(this: Source) ?*anyopaque { switch (this) { .pipe => |pipe| return pipe.data, .tty => |tty| return tty.data, .file => |file| return file.fs.data, } } pub fn ref(this: Source) void { switch (this) { .pipe => this.pipe.ref(), .tty => this.tty.ref(), .file => return, } } pub fn unref(this: Source) void { switch (this) { .pipe => this.pipe.unref(), .tty => this.tty.unref(), .file => return, } } pub fn hasRef(this: Source) bool { switch (this) { .pipe => return this.pipe.hasRef(), .tty => return this.tty.hasRef(), .file => return false, } } pub fn openPipe(loop: *uv.Loop, fd: bun.FileDescriptor, ipc: bool) bun.JSC.Maybe(*Source.Pipe) { log("openPipe (fd = {})", .{fd}); const pipe = bun.default_allocator.create(Source.Pipe) catch bun.outOfMemory(); switch (pipe.init(loop, ipc)) { .err => |err| { return .{ .err = err }; }, else => {}, } const file_fd = bun.uvfdcast(fd); return switch (pipe.open(file_fd)) { .err => |err| .{ .err = err, }, .result => .{ .result = pipe, }, }; } pub fn openTty(loop: *uv.Loop, fd: bun.FileDescriptor) bun.JSC.Maybe(*Source.Tty) { log("openTTY (fd = {})", .{fd}); const tty = bun.default_allocator.create(Source.Tty) catch bun.outOfMemory(); return switch (tty.init(loop, bun.uvfdcast(fd))) { .err => |err| .{ .err = err }, .result => .{ .result = tty }, }; } pub fn openFile(fd: bun.FileDescriptor) bun.JSC.Maybe(*Source.File) { log("openFile (fd = {})", .{fd}); const file = bun.default_allocator.create(Source.File) catch bun.outOfMemory(); file.* = std.mem.zeroes(Source.File); file.file = bun.uvfdcast(fd); return .{ .result = file }; } pub fn open(loop: *uv.Loop, fd: bun.FileDescriptor) bun.JSC.Maybe(Source) { log("open (fd = {})", .{fd}); const rc = bun.windows.GetFileType(fd.cast()); if (rc == bun.windows.FILE_TYPE_CHAR) .{ .tty = switch (openTty(loop, fd)) { .result => |tty| return .{ .result = .{ .tty = tty } }, .err => |err| return .{ .err = err }, } } else .{ .file = switch (openFile(fd)) { .result => |file| return .{ .result = .{ .file = file } }, .err => |err| return .{ .err = err }, }, }; } };