Você já usou streams em channel-chatter e já os descartou em boatswains-bilge. Este exercício é o seu primeiro stream personalizado: uma classe que implementa o protocolo, de modo que o mesmo código with-input-stream / read1 / stream-read1 que funcionava em um <string-reader> funcione no seu.
Você já conhece TUPLE: child < parent … de dragons-descendants, uma hierarquia de pai único em que os slots descem. O Factor tem uma segunda forma de estender o grafo de classes: os mixins abertos. Um MIXIN: m declara uma classe sem slots na qual outras classes podem entrar depois, com INSTANCE: c m. A associação é muitos-para-muitos: uma classe pode ser instância de quantos mixins quiser.
O protocolo de streams usa dois mixins para marcar qual metade da interface uma classe implementa:
INSTANCE: my-stream input-stream ! readable
INSTANCE: my-stream output-stream ! writable
Um stream pode ser um, o outro, ou os dois. Os métodos genéricos de input-stream (ou output-stream) então despacham para qualquer classe que tenha aderido ao mixin. É assim que read1, stream-contents, with-input-stream e outros do ambiente chegam até a sua classe.
Os mixins são abertos: você pode adicionar um novo membro depois que o mixin foi declarado, até mesmo em um vocabulário diferente. É esse o contraste com TUPLE: < parent, em que a relação é fixada quando a classe filha é declarada.
Os genéricos do protocolo ficam em io:
stream-read1 ( stream -- elt/f )
stream-read ( n stream -- seq/f )
stream-read-unsafe ( n buf stream -- count )
stream-write1 ( elt stream -- )
stream-write ( seq stream -- )
stream-flush ( stream -- )
stream-element-type ( stream -- type )
stream-read1 retorna o próximo byte (ou f no fim do stream); stream-write1 escreve um. stream-read-unsafe é a leitura em lote de mais baixo nível que a maioria dos streams de entrada fornece; stream-read é construído em cima dela e cuida da alocação. stream-element-type diz se o stream lida com bytes (+byte+) ou caracteres (+character+); quando você envolve outro stream, a implementação mais simples apenas delega para o stream subjacente.
destructors
Streams são descartáveis: um stream personalizado estende disposable e implementa dispose*. É o framework de boatswains-bilge, aplicado a uma classe de stream:
TUPLE: my-stream < disposable underlying ;
: <my-stream> ( underlying -- s )
my-stream new-disposable swap >>underlying ;
M: my-stream dispose* underlying>> dispose ;
Depois que isso estiver pronto, todos os combinadores with-… de channel-chatter funcionam no seu stream automaticamente.
Você é o radiotelegrafista de um cargueiro. O sinal chega por
uma linha ruidosa, com o barulho das máquinas do navio, estática
do tempo e conversas estrangeiras ocasionais, tudo intercalado
com o Morse que você está tentando ouvir. Para captar a
mensagem, você passa o fio por um dispositivo de fita que
remove tudo, exceto os símbolos Morse válidos (., - e o
espaço que separa as letras).
Seu trabalho é construir a fita como um fluxo de entrada personalizado do Factor.
Defina uma tupla tape que estende disposable e contém um
slot, wire, para o fluxo de entrada subjacente.
TUPLE: tape < disposable wire ;
Depois escreva o construtor <tape> ( wire -- tape ). Use
new-disposable (e não new) para que o framework do destrutor
registre a fita, e guarde o fluxo subjacente no slot wire.
Declare que tape é um input-stream:
INSTANCE: tape input-stream
Assim, os combinadores padrão do protocolo despacham para a sua classe.
Implemente M: tape stream-read1 ( tape -- elt/f ). Leia bytes
do fio subjacente até encontrar um de CHAR: ., CHAR: - ou
CHAR: \s (espaço). Retorne esse byte. Se o fio retornar f
(fim de fluxo), retorne f também: a fita acabou.
"x.y -ab cz" <string-reader> <tape>
[ stream-read1 ] [ stream-read1 ] [ stream-read1 ] tri
! => CHAR: . CHAR: - CHAR: \s
Implemente M: tape stream-element-type ( tape -- type )
delegando ao fio: a fita não muda o tipo de elementos que estão
sendo lidos.
Implemente M: tape dispose* ( tape -- ). O framework chama o
seu método exatamente uma vez por dispose; basta descartar o
fio subjacente.
Com essas cinco peças no lugar, a fita funciona como um fluxo de
entrada comum: with-input-stream, stream-read e as demais
palavras do protocolo despacham automaticamente para os seus
métodos.
Crie sua conta no Exercism para aprender e dominar Factor com 47 conceitos163 exercícios e mentoria humana de verdade, tudo de graça.