fix function getters

This commit is contained in:
Folkert 2023-02-25 15:47:20 +01:00
parent 033618f3f4
commit 35980e50b8
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
5 changed files with 218 additions and 220 deletions

View file

@ -59,7 +59,6 @@ pub struct Op {
pointer: *mut union_Op,
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
@ -87,7 +86,6 @@ union union_Op {
target_arch = "x86_64"
))]
//TODO HAS CLOSURE 2
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
@ -95,20 +93,21 @@ union union_Op {
target_arch = "x86",
target_arch = "x86_64"
))]
#[repr(C)]
pub struct RocFunction_66 {
pub closure_data: *mut u8,
pub closure_data: Vec<u8>,
}
impl RocFunction_66 {
pub fn force_thunk(self, arg_0: ()) -> Op {
pub fn force_thunk(mut self, arg_0: ()) -> Op {
extern "C" {
fn roc__mainForHost_0_caller(output: *mut Op, arg_0: (), closure_data: *mut u8);
fn roc__mainForHost_0_caller(arg_0: &(), closure_data: *mut u8, output: *mut Op);
}
let mut output = std::mem::MaybeUninit::uninit();
unsafe { roc__mainForHost_0_caller(output.as_mut_ptr(), arg_0, self.closure_data) };
unsafe {
roc__mainForHost_0_caller(&arg_0, self.closure_data.as_mut_ptr(), output.as_mut_ptr())
};
unsafe { output.assume_init() }
}
}
@ -120,20 +119,21 @@ impl RocFunction_66 {
target_arch = "x86",
target_arch = "x86_64"
))]
#[repr(C)]
pub struct RocFunction_67 {
pub closure_data: *mut u8,
pub closure_data: Vec<u8>,
}
impl RocFunction_67 {
pub fn force_thunk(self, arg_0: ()) -> Op {
pub fn force_thunk(mut self, arg_0: ()) -> Op {
extern "C" {
fn roc__mainForHost_1_caller(output: *mut Op, arg_0: (), closure_data: *mut u8);
fn roc__mainForHost_1_caller(arg_0: &(), closure_data: *mut u8, output: *mut Op);
}
let mut output = std::mem::MaybeUninit::uninit();
unsafe { roc__mainForHost_1_caller(output.as_mut_ptr(), arg_0, self.closure_data) };
unsafe {
roc__mainForHost_1_caller(&arg_0, self.closure_data.as_mut_ptr(), output.as_mut_ptr())
};
unsafe { output.assume_init() }
}
}
@ -161,28 +161,18 @@ impl Op {
if untagged.is_null() {
None
} else {
unsafe {
Some(&*untagged.sub(1))
}
unsafe { Some(&*untagged.sub(1)) }
}
}
#[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// Returns which variant this tag union holds. Note that this never includes a payload!
pub fn discriminant(&self) -> discriminant_Op {
// The discriminant is stored in the unused bytes at the end of the recursive pointer
unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b11) }
}
#[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// Internal helper
fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer
@ -192,11 +182,7 @@ impl Op {
tagged as *mut union_Op
}
#[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// Internal helper
fn union_pointer(&self) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer
@ -229,14 +215,12 @@ impl Op {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
extern "C" {
#[link_name = "roc__getter__2"]
#[link_name = "roc__getter__2_generic"]
fn getter(_: *mut roc_std::RocStr, _: *const Op);
}
let mut ret = core::mem::MaybeUninit::uninit();
getter(ret.as_mut_ptr(), self);
ret.assume_init()
}
@ -254,15 +238,21 @@ impl Op {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
extern "C" {
#[link_name = "roc__getter__3"]
fn getter(_: *mut RocFunction_67, _: *const Op);
#[link_name = "roc__roc__getter__3_size"]
fn size() -> usize;
#[link_name = "roc__getter__3_generic"]
fn getter(_: *mut u8, _: *const Op);
}
let mut ret = core::mem::MaybeUninit::uninit();
// dumb heap allocation for now
let mut bytes = vec![0xAAu8; size()];
getter(ret.as_mut_ptr(), self);
getter(bytes.as_mut_ptr(), self);
ret.assume_init()
RocFunction_67 {
closure_data: bytes,
}
}
#[cfg(any(
@ -274,32 +264,28 @@ impl Op {
))]
/// Construct a tag named `StderrWrite`, with the appropriate payload
pub fn StderrWrite(arg: Op_StderrWrite) -> Self {
let size = core::mem::size_of::<union_Op>();
let align = core::mem::align_of::<union_Op>() as u32;
let size = core::mem::size_of::<union_Op>();
let align = core::mem::align_of::<union_Op>() as u32;
unsafe {
let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
unsafe {
let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
*ptr = union_Op {
StderrWrite: core::mem::ManuallyDrop::new(arg)
};
*ptr = union_Op {
StderrWrite: core::mem::ManuallyDrop::new(arg),
};
Self {
pointer: Self::tag_discriminant(ptr, discriminant_Op::StderrWrite),
}
Self {
pointer: Self::tag_discriminant(ptr, discriminant_Op::StderrWrite),
}
}
}
#[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -318,16 +304,12 @@ impl Op {
payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
@ -351,14 +333,12 @@ impl Op {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
extern "C" {
#[link_name = "roc__getter__2"]
#[link_name = "roc__getter__2_generic"]
fn getter(_: *mut roc_std::RocStr, _: *const Op);
}
let mut ret = core::mem::MaybeUninit::uninit();
getter(ret.as_mut_ptr(), self);
ret.assume_init()
}
@ -376,15 +356,21 @@ impl Op {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
extern "C" {
#[link_name = "roc__getter__3"]
fn getter(_: *mut RocFunction_66, _: *const Op);
#[link_name = "roc__roc__getter__3_size"]
fn size() -> usize;
#[link_name = "roc__getter__3_generic"]
fn getter(_: *mut u8, _: *const Op);
}
let mut ret = core::mem::MaybeUninit::uninit();
// dumb heap allocation for now
let mut bytes = vec![0xAAu8; size()];
getter(ret.as_mut_ptr(), self);
getter(bytes.as_mut_ptr(), self);
ret.assume_init()
RocFunction_66 {
closure_data: bytes,
}
}
#[cfg(any(
@ -396,32 +382,28 @@ impl Op {
))]
/// Construct a tag named `StdoutWrite`, with the appropriate payload
pub fn StdoutWrite(arg: Op_StdoutWrite) -> Self {
let size = core::mem::size_of::<union_Op>();
let align = core::mem::align_of::<union_Op>() as u32;
let size = core::mem::size_of::<union_Op>();
let align = core::mem::align_of::<union_Op>() as u32;
unsafe {
let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
unsafe {
let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
*ptr = union_Op {
StdoutWrite: core::mem::ManuallyDrop::new(arg)
};
*ptr = union_Op {
StdoutWrite: core::mem::ManuallyDrop::new(arg),
};
Self {
pointer: Self::tag_discriminant(ptr, discriminant_Op::StdoutWrite),
}
Self {
pointer: Self::tag_discriminant(ptr, discriminant_Op::StdoutWrite),
}
}
}
#[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -440,16 +422,12 @@ impl Op {
payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
@ -459,20 +437,14 @@ impl Op {
&payload
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
/// Returns which variant this tag union holds. Note that this never includes a payload!
pub fn discriminant(&self) -> discriminant_Op {
// The discriminant is stored in the unused bytes at the end of the recursive pointer
unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b111) }
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
/// Internal helper
fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer
@ -482,25 +454,19 @@ impl Op {
tagged as *mut union_Op
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
/// Internal helper
fn union_pointer(&self) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer
((self.pointer as usize) & (!0b111 as usize)) as *mut union_Op
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -519,15 +485,12 @@ impl Op {
payload
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
@ -537,15 +500,12 @@ impl Op {
&payload
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -564,15 +524,12 @@ impl Op {
payload
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
@ -601,17 +558,23 @@ impl Drop for Op {
if needs_dealloc {
// Drop the payload first.
match self.discriminant() {
discriminant_Op::Done => {}
discriminant_Op::StderrWrite => unsafe { core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StderrWrite) },
discriminant_Op::StdoutWrite => unsafe { core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StdoutWrite) },
}
match self.discriminant() {
discriminant_Op::Done => {}
discriminant_Op::StderrWrite => unsafe {
core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StderrWrite)
},
discriminant_Op::StdoutWrite => unsafe {
core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StdoutWrite)
},
}
// Dealloc the pointer
let alignment = core::mem::align_of::<Self>().max(core::mem::align_of::<roc_std::Storage>());
let alignment =
core::mem::align_of::<Self>().max(core::mem::align_of::<roc_std::Storage>());
unsafe { crate::roc_dealloc(storage.as_ptr().cast(), alignment as u32); }
unsafe {
crate::roc_dealloc(storage.as_ptr().cast(), alignment as u32);
}
} else {
// Write the storage back.
storage.set(new_storage);
@ -631,15 +594,19 @@ impl PartialEq for Op {
target_arch = "x86_64"
))]
fn eq(&self, other: &Self) -> bool {
if self.discriminant() != other.discriminant() {
return false;
}
if self.discriminant() != other.discriminant() {
return false;
}
unsafe {
unsafe {
match self.discriminant() {
discriminant_Op::Done => true,
discriminant_Op::StderrWrite => (&*self.union_pointer()).StderrWrite == (&*other.union_pointer()).StderrWrite,
discriminant_Op::StdoutWrite => (&*self.union_pointer()).StdoutWrite == (&*other.union_pointer()).StdoutWrite,
discriminant_Op::StderrWrite => {
(&*self.union_pointer()).StderrWrite == (&*other.union_pointer()).StderrWrite
}
discriminant_Op::StdoutWrite => {
(&*self.union_pointer()).StdoutWrite == (&*other.union_pointer()).StdoutWrite
}
}
}
}
@ -662,8 +629,12 @@ impl PartialOrd for Op {
unsafe {
match self.discriminant() {
discriminant_Op::Done => Some(core::cmp::Ordering::Equal),
discriminant_Op::StderrWrite => (&*self.union_pointer()).StderrWrite.partial_cmp(&(&*other.union_pointer()).StderrWrite),
discriminant_Op::StdoutWrite => (&*self.union_pointer()).StdoutWrite.partial_cmp(&(&*other.union_pointer()).StdoutWrite),
discriminant_Op::StderrWrite => (&*self.union_pointer())
.StderrWrite
.partial_cmp(&(&*other.union_pointer()).StderrWrite),
discriminant_Op::StdoutWrite => (&*self.union_pointer())
.StdoutWrite
.partial_cmp(&(&*other.union_pointer()).StdoutWrite),
}
}
}
@ -678,16 +649,20 @@ impl Ord for Op {
target_arch = "x86_64"
))]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
match self.discriminant().cmp(&other.discriminant()) {
core::cmp::Ordering::Equal => {}
not_eq => return not_eq,
}
match self.discriminant().cmp(&other.discriminant()) {
core::cmp::Ordering::Equal => {}
not_eq => return not_eq,
}
unsafe {
unsafe {
match self.discriminant() {
discriminant_Op::Done => core::cmp::Ordering::Equal,
discriminant_Op::StderrWrite => (&*self.union_pointer()).StderrWrite.cmp(&(&*other.union_pointer()).StderrWrite),
discriminant_Op::StdoutWrite => (&*self.union_pointer()).StdoutWrite.cmp(&(&*other.union_pointer()).StdoutWrite),
discriminant_Op::StderrWrite => (&*self.union_pointer())
.StderrWrite
.cmp(&(&*other.union_pointer()).StderrWrite),
discriminant_Op::StdoutWrite => (&*self.union_pointer())
.StdoutWrite
.cmp(&(&*other.union_pointer()).StdoutWrite),
}
}
}
@ -711,7 +686,7 @@ impl Clone for Op {
}
Self {
pointer: self.pointer
pointer: self.pointer,
}
}
}
@ -724,16 +699,17 @@ impl core::hash::Hash for Op {
target_arch = "x86",
target_arch = "x86_64"
))]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) { match self.discriminant() {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
match self.discriminant() {
discriminant_Op::Done => discriminant_Op::Done.hash(state),
discriminant_Op::StderrWrite => unsafe {
discriminant_Op::StderrWrite.hash(state);
(&*self.union_pointer()).StderrWrite.hash(state);
},
discriminant_Op::StderrWrite.hash(state);
(&*self.union_pointer()).StderrWrite.hash(state);
},
discriminant_Op::StdoutWrite => unsafe {
discriminant_Op::StdoutWrite.hash(state);
(&*self.union_pointer()).StdoutWrite.hash(state);
},
discriminant_Op::StdoutWrite.hash(state);
(&*self.union_pointer()).StdoutWrite.hash(state);
},
}
}
}
@ -752,12 +728,14 @@ impl core::fmt::Debug for Op {
unsafe {
match self.discriminant() {
discriminant_Op::Done => f.write_str("Done"),
discriminant_Op::StderrWrite => f.debug_tuple("StderrWrite")
// TODO HAS CLOSURE
.finish(),
discriminant_Op::StdoutWrite => f.debug_tuple("StdoutWrite")
// TODO HAS CLOSURE
.finish(),
discriminant_Op::StderrWrite => f
.debug_tuple("StderrWrite")
// TODO HAS CLOSURE
.finish(),
discriminant_Op::StdoutWrite => f
.debug_tuple("StdoutWrite")
// TODO HAS CLOSURE
.finish(),
}
}
}