about summary refs log tree commit diff stats
path: root/088file.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-12-11 16:18:18 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-12-11 16:18:18 -0800
commit294b2ab35983ebe95698835bb54bca8bd3eec101 (patch)
treefbc74bea6cefd7b8f527d36a7b7c6804dd886414 /088file.mu
parentd5c86dfd8706e6b3ceee7843464797e6fcad4259 (diff)
downloadmu-294b2ab35983ebe95698835bb54bca8bd3eec101.tar.gz
3705 - switch to tested file-system primitives
Diffstat (limited to '088file.mu')
-rw-r--r--088file.mu65
1 files changed, 57 insertions, 8 deletions
diff --git a/088file.mu b/088file.mu
index b7358327..69e72933 100644
--- a/088file.mu
+++ b/088file.mu
@@ -1,5 +1,12 @@
 # Wrappers around file system primitives that take a 'resources' object and
 # are thus easier to test.
+#
+# - start-reading - asynchronously open a file, returning a channel source for
+#   receiving the results
+# - start-writing - asynchronously open a file, returning a channel sink for
+#   the data to write
+# - slurp - synchronously read from a file
+# - dump - synchronously write to a file
 
 container resources [
   lock:bool
@@ -11,25 +18,42 @@ container resource [
   contents:text
 ]
 
-def start-reading resources:&:resources, filename:text -> contents:&:source:char [
+def start-reading resources:&:resources, filename:text -> contents:&:source:char, error?:bool [
   local-scope
   load-ingredients
+  error? <- copy 0/false
   {
     break-unless resources
     # fake file system
-    contents <- start-reading-from-fake-resources resources, filename
+    contents, error? <- start-reading-from-fake-resource resources, filename
     return
   }
   # real file system
   file:num <- $open-file-for-reading filename
-  assert file, [file not found]
+  return-unless file, 0/contents, 1/error?
   contents:&:source:char, sink:&:sink:char <- new-channel 30
   start-running receive-from-file file, sink
 ]
 
-def start-reading-from-fake-resources resources:&:resources, resource:text -> contents:&:source:char [
+def slurp resources:&:resources, filename:text -> contents:text, error?:bool [
   local-scope
   load-ingredients
+  source:&:source:char, error?:bool <- start-reading resources, filename
+  return-if error?, 0/contents
+  buf:&:buffer <- new-buffer 30/capacity
+  {
+    c:char, done?:bool, source <- read source
+    break-if done?
+    buf <- append buf, c
+    loop
+  }
+  contents <- buffer-to-array buf
+]
+
+def start-reading-from-fake-resource resources:&:resources, resource:text -> contents:&:source:char, error?:bool [
+  local-scope
+  load-ingredients
+  error? <- copy 0/no-error
   i:num <- copy 0
   data:&:@:resource <- get *resources, data:offset
   len:num <- length *data
@@ -46,7 +70,7 @@ def start-reading-from-fake-resources resources:&:resources, resource:text -> co
     start-running receive-from-text curr-contents, sink
     return
   }
-  return 0/not-found
+  return 0/not-found, 1/error
 ]
 
 def receive-from-file file:num, sink:&:sink:char -> sink:&:sink:char [
@@ -78,18 +102,20 @@ def receive-from-text contents:text, sink:&:sink:char -> sink:&:sink:char [
   sink <- close sink
 ]
 
-def start-writing resources:&:resources, filename:text -> sink:&:sink:char, routine-id:num [
+def start-writing resources:&:resources, filename:text -> sink:&:sink:char, routine-id:num, error?:bool [
   local-scope
   load-ingredients
+  error? <- copy 0/false
   source:&:source:char, sink:&:sink:char <- new-channel 30
   {
     break-unless resources
     # fake file system
-    routine-id <- start-running transmit-to-fake-file resources, filename, source
+    routine-id <- start-running transmit-to-fake-resource resources, filename, source
     return
   }
   # real file system
   file:num <- $open-file-for-writing filename
+  return-unless file, 0/sink, 0/routine-id, 1/error?
   {
     break-if file
     msg:text <- append [no such file: ] filename
@@ -98,6 +124,29 @@ def start-writing resources:&:resources, filename:text -> sink:&:sink:char, rout
   routine-id <- start-running transmit-to-file file, source
 ]
 
+def dump resources:&:resources, filename:text, contents:text -> resources:&:resources, error?:bool [
+  local-scope
+  load-ingredients
+  # todo: really create an empty file
+  return-unless contents, resources, 0/no-error
+  sink-file:&:sink:char, write-routine:num, error?:bool <- start-writing resources, filename
+  return-if error?
+  i:num <- copy 0
+  len:num <- length *contents
+  {
+    done?:bool <- greater-or-equal i, len
+    break-if done?
+    c:char <- index *contents, i
+    sink-file <- write sink-file, c
+    i <- add i, 1
+    loop
+  }
+  close sink-file
+  # make sure to wait for the file to be actually written to disk
+  # (Mu practices structured concurrency: http://250bpm.com/blog:71)
+  wait-for-routine write-routine
+]
+
 def transmit-to-file file:num, source:&:source:char -> source:&:source:char [
   local-scope
   load-ingredients
@@ -110,7 +159,7 @@ def transmit-to-file file:num, source:&:source:char -> source:&:source:char [
   file <- $close-file file
 ]
 
-def transmit-to-fake-file resources:&:resources, filename:text, source:&:source:char -> resources:&:resources, source:&:source:char [
+def transmit-to-fake-resource resources:&:resources, filename:text, source:&:source:char -> resources:&:resources, source:&:source:char [
   local-scope
   load-ingredients
   lock:location <- get-location *resources, lock:offset