JNevens
JNevens

Reputation: 12012

How to use pipes and custom-ports in Racket

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

Answers (1)

Greg Hendershott
Greg Hendershott

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

Related Questions