Reputation: 12012
I'm trying to use a custom port or pipes in Racket. I would want to write a message to a pipe, the pipe checks the message, and depending on the message, it returns another message or a certain value.
I've tried something like this:
(define (write-s msg)
(let-values ([(in-port transmitting) (make-pipe)]
[(receiving out-port) (make-pipe)])
(write msg out-port)
(let ((message (read receiving)))
(if (equal? message '(DOGE))
(write '(SO AMAZE) transmitting)
'do-nothing)
(if (equal? message '(MUCH PIPES))
(write '(WOW RACKET) transmitting)
'do-nothing))
(read in-port)))
Upvotes: 1
Views: 657
Reputation: 16260
I suggest defining a simple helper function, make-codec-input-port
, that lets you create an input-port from an original input-port and a "codec" function. The key point here -- which wasn't obvious to me from the Racket documentation for make-pipe
-- is that you want to run a thread
that calls the codec function.
Here I show a trivial codec that replaces every #\a
character with #\b
. You could change its match
statement to do something more interesting.
#lang racket
;; Given an input-port and a codec function, return a new input-port
;; that is the encoded version. `codec` is (input-port? output-port?
;; -> any). For example can be deflate, inflate, gzip-through-ports,
;; gunzip-through-ports, copy-port (the identity function for this),
;; or your own such function.
(define codec-buffer-size (make-parameter 1024))
(define (make-codec-input-port in codec [name #f])
(define-values (pin pout) (make-pipe (codec-buffer-size) name name))
(thread (lambda ()
(codec in pout)
(close-output-port pout)))
pin)
;; Example of a codec function.
(define (replace-a-with-b in out) ;; (input-port? output-port? -> any)
(let loop ()
(define ch (read-char in))
(unless (eof-object? ch)
(write-char (match ch
[#\a #\b]
[x x])
out)
(loop))))
;; You could also write the codec function a bit more simply using
;; `in-port`:
(define (replace-a-with-b in out) ;; (input-port? output-port? -> any)
(for ([ch (in-port read-char in)])
(write-char (match ch
[#\a #\b]
[x x])
out)))
;; Example direct use of the codec function.
(let ()
(define orig-in (open-input-string "axaxax"))
(replace-a-with-b orig-in (current-output-port)))
;; => bxbxbx
;; Example use of the encoded input port. With this, a user of the
;; port need not know anything about the codec function.
(let ()
(define orig-in (open-input-string "axaxax"))
(define encoded-in (make-codec-input-port orig-in replace-a-with-b))
(port->string encoded-in))
;; => "bxbxbx"
Upvotes: 2