Merge pull request #4844 from unisonweb/kylegoetz-udp

Kylegoetz udp
This commit is contained in:
Arya Irani 2024-05-10 13:03:50 -04:00 committed by GitHub
commit 4ce7cdf5d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 1485 additions and 932 deletions

View File

@ -15,7 +15,7 @@ be listed here, please [file a ticket](https://github.com/unisonweb/unison/issue
This file was generated using [unisonweb/credits-generator](http://github.com/unisonweb/credits-generator).
### Listing
### Listing
These are listed in alphabetical order.
| Package name | License |
@ -109,6 +109,7 @@ These are listed in alphabetical order.
| [network-bsd-2.8.1.0](https://hackage.haskell.org/package/network-bsd-2.8.1.0) | [BSD3](https://hackage.haskell.org/package/network-bsd-2.8.1.0/src/LICENSE) |
| [network-info-0.2.0.10](https://hackage.haskell.org/package/network-info-0.2.0.10) | [BSD3](https://hackage.haskell.org/package/network-info-0.2.0.10/src/LICENSE) |
| [network-simple-0.4.5](https://hackage.haskell.org/package/network-simple-0.4.5) | [BSD3](https://hackage.haskell.org/package/network-simple-0.4.5/src/LICENSE) |
| [network-udp-0.0.0](https://hackage.haskell.org/package/network-udp-0.0.0) | [BSD3](https://hackage.haskell.org/package/network-udp-0.0.0/src/LICENSE) |
| [nonempty-containers-0.3.3.0](https://hackage.haskell.org/package/nonempty-containers-0.3.3.0) | [BSD3](https://hackage.haskell.org/package/nonempty-containers-0.3.3.0/src/LICENSE) |
| [nonempty-vector-0.2.0.2](https://hackage.haskell.org/package/nonempty-vector-0.2.0.2) | [BSD3](https://hackage.haskell.org/package/nonempty-vector-0.2.0.2/src/LICENSE) |
| [parallel-3.2.2.0](https://hackage.haskell.org/package/parallel-3.2.2.0) | [BSD3](https://hackage.haskell.org/package/parallel-3.2.2.0/src/LICENSE) |

View File

@ -60,6 +60,7 @@ dependencies:
- http-media
- http-types
- IntervalMap
- iproute
- lens
- lucid
- megaparsec
@ -73,6 +74,7 @@ dependencies:
- natural-transformation
- network
- network-simple
- network-udp
- network-uri
- nonempty-containers
- open-browser

View File

@ -246,7 +246,10 @@ builtinTypesSrc =
B' "MutableArray" CT.Data,
B' "ImmutableByteArray" CT.Data,
B' "MutableByteArray" CT.Data,
B' "Char.Class" CT.Data
B' "Char.Class" CT.Data,
B' "UDPSocket" CT.Data,
B' "ListenSocket" CT.Data,
B' "ClientSockAddr" CT.Data
]
-- rename these to "builtin" later, when builtin means intrinsic as opposed to
@ -815,6 +818,17 @@ ioBuiltins =
("IO.serverSocket.impl.v3", optionalt text --> text --> iof socket),
("IO.listen.impl.v3", socket --> iof unit),
("IO.clientSocket.impl.v3", text --> text --> iof socket),
("IO.UDP.clientSocket.impl.v1", text --> text --> iof udpSocket),
("IO.UDP.ClientSockAddr.toText.v1", udpClientSockAddr --> text),
("IO.UDP.UDPSocket.toText.impl.v1", udpSocket --> text),
("IO.UDP.UDPSocket.close.impl.v1", udpSocket --> iof unit),
("IO.UDP.serverSocket.impl.v1", text --> text --> iof udpListenSocket),
("IO.UDP.ListenSocket.recvFrom.impl.v1", udpListenSocket --> iof (tuple [bytes, udpClientSockAddr])),
("IO.UDP.ListenSocket.sendTo.impl.v1", udpListenSocket --> bytes --> udpClientSockAddr --> iof unit),
("IO.UDP.ListenSocket.toText.impl.v1", udpListenSocket --> text),
("IO.UDP.ListenSocket.close.impl.v1", udpListenSocket --> iof unit),
("IO.UDP.UDPSocket.recv.impl.v1", udpSocket --> iof bytes),
("IO.UDP.UDPSocket.send.impl.v1", udpSocket --> bytes --> iof unit),
("IO.closeSocket.impl.v3", socket --> iof unit),
("IO.socketPort.impl.v3", socket --> iof nat),
("IO.socketAccept.impl.v3", socket --> iof socket),
@ -1055,6 +1069,12 @@ handle = Type.fileHandle ()
phandle = Type.processHandle ()
unit = DD.unitType ()
udpSocket, udpListenSocket, udpClientSockAddr :: Type
udpSocket = Type.udpSocket ()
udpListenSocket = Type.udpListenSocket ()
udpClientSockAddr = Type.udpClientSockAddr ()
tls, tlsClientConfig, tlsServerConfig, tlsSignedCert, tlsPrivateKey, tlsVersion, tlsCipher :: Type
tls = Type.ref () Type.tlsRef
tlsClientConfig = Type.ref () Type.tlsClientConfigRef

View File

@ -356,6 +356,9 @@ builtinConstraintTree =
flip Type.ref Type.filePathRef,
Type.threadId,
Type.socket,
Type.udpSocket,
Type.udpListenSocket,
Type.udpClientSockAddr,
Type.processHandle,
Type.ibytearrayType,
flip Type.ref Type.charClassRef,

View File

@ -52,6 +52,7 @@ import Data.IORef as SYS
readIORef,
writeIORef,
)
import Data.IP (IP)
import Data.Map qualified as Map
import Data.PEM (PEM, pemContent, pemParseLBS)
import Data.Set (insert)
@ -81,9 +82,23 @@ import Network.Simple.TCP as SYS
import Network.Socket as SYS
( Socket,
accept,
socketPort,
socketPort, PortNumber,
)
import Network.TLS as TLS
import Network.UDP as UDP
( UDPSocket (..),
ClientSockAddr,
ListenSocket,
clientSocket,
close,
recv,
recvFrom,
send,
sendTo,
serverSocket,
stop,
)
import Network.TLS.Extra.Cipher as Cipher
import System.Clock (Clock (..), getTime, nsec, sec)
import System.Directory as SYS
@ -1544,6 +1559,22 @@ outIoFailBool stack1 stack2 stack3 extra fail result =
)
]
outIoFailTup :: forall v . (Var v) => v -> v -> v -> v -> v -> v -> v -> v -> ANormal v
outIoFailTup stack1 stack2 stack3 stack4 stack5 extra fail result =
TMatch result . MatchSum $
mapFromList
[ failureCase stack1 stack2 stack3 extra fail,
( 1,
([BX, BX],
TAbss [stack1, stack2]
. TLetD stack3 BX (TCon Ty.unitRef 0 [])
. TLetD stack4 BX (TCon Ty.pairRef 0 [stack2, stack3])
. TLetD stack5 BX (TCon Ty.pairRef 0 [stack1, stack4])
$ right stack5
)
)
]
outIoFailG ::
(Var v) =>
v ->
@ -1767,6 +1798,14 @@ boxToEFBox =
where
(arg, result, stack1, stack2, stack3, any, fail) = fresh
-- a -> Either Failure (b, c)
boxToEFTup :: ForeignOp
boxToEFTup =
inBx arg result $
outIoFailTup stack1 stack2 stack3 stack4 stack5 extra fail result
where
(arg, result, stack1, stack2, stack3, stack4, stack5, extra, fail) = fresh
-- a -> Either Failure (Maybe b)
boxToEFMBox :: ForeignOp
boxToEFMBox =
@ -1858,6 +1897,14 @@ boxBoxToEF0 =
where
(arg1, arg2, result, stack1, stack2, stack3, fail, unit) = fresh
-- a -> b -> c -> Either Failure ()
boxBoxBoxToEF0 :: ForeignOp
boxBoxBoxToEF0 =
inBxBxBx arg1 arg2 arg3 result $
outIoFailUnit stack1 stack2 stack3 fail unit result
where
(arg1, arg2, arg3, result, stack1, stack2, stack3, fail, unit) = fresh
-- a -> Either Failure Nat
boxToEFNat :: ForeignOp
boxToEFNat =
@ -2290,8 +2337,64 @@ mkForeignTlsE f = mkForeign $ \a -> fmap flatten (tryIO2 (tryIO1 (f a)))
flatten (Right (Right (Left e))) = Left e
flatten (Right (Right (Right a))) = Right a
declareUdpForeigns :: FDecl Symbol ()
declareUdpForeigns = do
declareForeign Tracked "IO.UDP.clientSocket.impl.v1" boxBoxToEFBox
. mkForeignIOF
$ \(host :: Util.Text.Text, port :: Util.Text.Text) ->
let hostStr = Util.Text.toString host
portStr = Util.Text.toString port
in UDP.clientSocket hostStr portStr True
declareForeign Tracked "IO.UDP.UDPSocket.recv.impl.v1" boxToEFBox
. mkForeignIOF
$ \(sock :: UDPSocket) -> Bytes.fromArray <$> UDP.recv sock
declareForeign Tracked "IO.UDP.UDPSocket.send.impl.v1" boxBoxToEF0
. mkForeignIOF
$ \(sock :: UDPSocket, bytes :: Bytes.Bytes) ->
UDP.send sock (Bytes.toArray bytes)
declareForeign Tracked "IO.UDP.UDPSocket.close.impl.v1" boxToEF0
. mkForeignIOF
$ \(sock :: UDPSocket) -> UDP.close sock
declareForeign Tracked "IO.UDP.ListenSocket.close.impl.v1" boxToEF0
. mkForeignIOF
$ \(sock :: ListenSocket) -> UDP.stop sock
declareForeign Tracked "IO.UDP.UDPSocket.toText.impl.v1" boxDirect
. mkForeign
$ \(sock :: UDPSocket) -> pure $ show sock
declareForeign Tracked "IO.UDP.serverSocket.impl.v1" boxBoxToEFBox
. mkForeignIOF
$ \(ip :: Util.Text.Text, port :: Util.Text.Text) ->
let maybeIp = readMaybe $ Util.Text.toString ip :: Maybe IP
maybePort = readMaybe $ Util.Text.toString port :: Maybe PortNumber
in case (maybeIp, maybePort) of
(Nothing, _) -> fail "Invalid IP Address"
(_, Nothing) -> fail "Invalid Port Number"
(Just ip, Just pt) -> UDP.serverSocket (ip, pt)
declareForeign Tracked "IO.UDP.ListenSocket.toText.impl.v1" boxDirect
. mkForeign
$ \(sock :: ListenSocket) -> pure $ show sock
declareForeign Tracked "IO.UDP.ListenSocket.recvFrom.impl.v1" boxToEFTup .
mkForeignIOF $ fmap (first Bytes.fromArray) <$> UDP.recvFrom
declareForeign Tracked "IO.UDP.ClientSockAddr.toText.v1" boxDirect
. mkForeign
$ \(sock :: ClientSockAddr) -> pure $ show sock
declareForeign Tracked "IO.UDP.ListenSocket.sendTo.impl.v1" boxBoxBoxToEF0 .
mkForeignIOF $ \(socket :: ListenSocket, bytes :: Bytes.Bytes, addr :: ClientSockAddr) ->
UDP.sendTo socket (Bytes.toArray bytes) addr
declareForeigns :: FDecl Symbol ()
declareForeigns = do
declareUdpForeigns
declareForeign Tracked "IO.openFile.impl.v3" boxIomrToEFBox $
mkForeignIOF $ \(fnameText :: Util.Text.Text, n :: Int) ->
let fname = Util.Text.toString fnameText

View File

@ -27,6 +27,7 @@ import Data.Primitive (ByteArray, MutableArray, MutableByteArray)
import Data.Tagged (Tagged (..))
import Data.X509 qualified as X509
import Network.Socket (Socket)
import Network.UDP (ListenSocket, UDPSocket, ClientSockAddr)
import Network.TLS qualified as TLS (ClientParams, Context, ServerParams)
import System.Clock (TimeSpec)
import System.IO (Handle)
@ -81,6 +82,10 @@ socketEq :: Socket -> Socket -> Bool
socketEq l r = l == r
{-# NOINLINE socketEq #-}
udpSocketEq :: UDPSocket -> UDPSocket -> Bool
udpSocketEq l r = l == r
{-# NOINLINE udpSocketEq #-}
refEq :: IORef () -> IORef () -> Bool
refEq l r = l == r
{-# NOINLINE refEq #-}
@ -157,6 +162,7 @@ ref2eq r
-- Ditto
| r == Ty.tvarRef = Just $ promote tvarEq
| r == Ty.socketRef = Just $ promote socketEq
| r == Ty.udpSocketRef = Just $ promote udpSocketEq
| r == Ty.refRef = Just $ promote refEq
| r == Ty.threadIdRef = Just $ promote tidEq
| r == Ty.marrayRef = Just $ promote marrEq
@ -230,6 +236,12 @@ instance BuiltinForeign Referent where foreignRef = Tagged Ty.termLinkRef
instance BuiltinForeign Socket where foreignRef = Tagged Ty.socketRef
instance BuiltinForeign ListenSocket where foreignRef = Tagged Ty.udpListenSocketRef
instance BuiltinForeign ClientSockAddr where foreignRef = Tagged Ty.udpClientSockAddrRef
instance BuiltinForeign UDPSocket where foreignRef = Tagged Ty.udpSocketRef
instance BuiltinForeign ThreadId where foreignRef = Tagged Ty.threadIdRef
instance BuiltinForeign TLS.ClientParams where foreignRef = Tagged Ty.tlsClientConfigRef

View File

@ -26,6 +26,7 @@ import Data.Time.Clock.POSIX (POSIXTime)
import Data.Word (Word16, Word32, Word64, Word8)
import GHC.IO.Exception (IOErrorType (..), IOException (..))
import Network.Socket (Socket)
import Network.UDP (UDPSocket)
import System.IO (BufferMode (..), Handle, IOMode, SeekMode)
import Unison.Builtin.Decls qualified as Ty
import Unison.Reference (Reference)
@ -139,6 +140,10 @@ instance ForeignConvention Socket where
readForeign = readForeignBuiltin
writeForeign = writeForeignBuiltin
instance ForeignConvention UDPSocket where
readForeign = readForeignBuiltin
writeForeign = writeForeignBuiltin
instance ForeignConvention ThreadId where
readForeign = readForeignBuiltin
writeForeign = writeForeignBuiltin

View File

@ -268,6 +268,7 @@ library
, http-client
, http-media
, http-types
, iproute
, lens
, lucid
, megaparsec
@ -281,6 +282,7 @@ library
, natural-transformation
, network
, network-simple
, network-udp
, network-uri
, nonempty-containers
, open-browser
@ -462,6 +464,7 @@ test-suite parser-typechecker-tests
, http-client
, http-media
, http-types
, iproute
, lens
, lucid
, megaparsec
@ -475,6 +478,7 @@ test-suite parser-typechecker-tests
, natural-transformation
, network
, network-simple
, network-udp
, network-uri
, nonempty-containers
, open-browser

View File

@ -30,6 +30,7 @@
unison/data-info
unison/chunked-seq
unison/primops
unison/builtin
unison/primops-generated
unison/builtin-generated)

View File

@ -47,6 +47,10 @@
builtin-tls.signedcert:typelink
builtin-tls.version:typelink
builtin-udpsocket:typelink
builtin-listensocket:typelink
builtin-clientsockaddr:typelink
bytevector
bytes
control

View File

@ -0,0 +1,4 @@
#lang racket/base
(require unison/udp)
(provide (all-from-out))

View File

@ -80,6 +80,9 @@
builtin-timespec:typelink
builtin-threadid:typelink
builtin-value:typelink
builtin-udpsocket:typelink
builtin-listensocket:typelink
builtin-clientsockaddr:typelink
builtin-crypto.hashalgorithm:typelink
builtin-char.class:typelink
@ -440,6 +443,9 @@
(define builtin-timespec:typelink (unison-typelink-builtin "TimeSpec"))
(define builtin-threadid:typelink (unison-typelink-builtin "ThreadId"))
(define builtin-value:typelink (unison-typelink-builtin "Value"))
(define builtin-udpsocket:typelink (unison-typelink-builtin "UDPSocket"))
(define builtin-listensocket:typelink (unison-typelink-builtin "ListenSocket"))
(define builtin-clientsockaddr:typelink (unison-typelink-builtin "ClientSockAddr"))
(define builtin-crypto.hashalgorithm:typelink
(unison-typelink-builtin "crypto.HashAlgorithm"))

View File

@ -0,0 +1,31 @@
#lang racket/base
(require racket/exn
unison/data ; exception
unison/data-info ; ref-*
unison/chunked-seq
unison/core) ; exception->string, chunked-string
(provide handle-errors)
(define (handle-errors fn)
(with-handlers
[[exn:fail:network?
(lambda (e)
(exception
ref-iofailure:typelink
(exception->string e)
ref-unit-unit))]
[exn:fail:contract?
(lambda (e)
(exception
ref-miscfailure:typelink
(exception->string e)
ref-unit-unit))]
[(lambda _ #t)
(lambda (e)
(exception
ref-miscfailure:typelink
(string->chunked-string
(format "Unknown exception ~a" (exn->string e)))
ref-unit-unit))]]
(fn)))

View File

@ -186,6 +186,29 @@
builtin-TypeLink.toReference
builtin-TypeLink.toReference:termlink
builtin-IO.UDP.clientSocket.impl.v1
builtin-IO.UDP.clientSocket.impl.v1:termlink
builtin-IO.UDP.UDPSocket.recv.impl.v1
builtin-IO.UDP.UDPSocket.recv.impl.v1:termlink
builtin-IO.UDP.UDPSocket.send.impl.v1
builtin-IO.UDP.UDPSocket.send.impl.v1:termlink
builtin-IO.UDP.UDPSocket.close.impl.v1
builtin-IO.UDP.UDPSocket.close.impl.v1:termlink
builtin-IO.UDP.ListenSocket.close.impl.v1
builtin-IO.UDP.ListenSocket.close.impl.v1:termlink
builtin-IO.UDP.UDPSocket.toText.impl.v1
builtin-IO.UDP.UDPSocket.toText.impl.v1:termlink
builtin-IO.UDP.serverSocket.impl.v1
builtin-IO.UDP.serverSocket.impl.v1:termlink
builtin-IO.UDP.ListenSocket.toText.impl.v1
builtin-IO.UDP.ListenSocket.toText.impl.v1:termlink
builtin-IO.UDP.ListenSocket.recvFrom.impl.v1
builtin-IO.UDP.ListenSocket.recvFrom.impl.v1:termlink
builtin-IO.UDP.ClientSockAddr.toText.v1
builtin-IO.UDP.ClientSockAddr.toText.v1:termlink
builtin-IO.UDP.ListenSocket.sendTo.impl.v1
builtin-IO.UDP.ListenSocket.sendTo.impl.v1:termlink
unison-FOp-internal.dataTag
unison-FOp-Char.toText
; unison-FOp-Code.dependencies
@ -645,6 +668,7 @@
(unison murmurhash)
(unison tls)
(unison tcp)
(unison udp)
(unison gzip)
(unison zlib)
(unison concurrent)

View File

@ -103,6 +103,17 @@
(sandbox-builtin "IO.getFileSize.impl.v3")
(sandbox-builtin "IO.serverSocket.impl.v3")
(sandbox-builtin "Socket.toText")
(sandbox-builtin "UDP.clientSocket.impl.v1")
(sandbox-builtin "UDP.serverSocket.impl.v1")
(sandbox-builtin "UDP.UDPSocket.close.impl.v1")
(sandbox-builtin "UDP.UDPSocket.recv.impl.v1")
(sandbox-builtin "UDP.UDPSocket.send.impl.v1")
(sandbox-builtin "UDP.ListenSocket.close.impl.v1")
(sandbox-builtin "UDP.UDPSocket.toText.impl.v1")
(sandbox-builtin "UDP.ListenSocket.toText.impl.v1")
(sandbox-builtin "UDP.ListenSocket.recvFrom.impl.v1")
(sandbox-builtin "UDP.ClientSockAddr.toText.v1")
(sandbox-builtin "UDP.ListenSocket.sendTo.impl.v1")
(sandbox-builtin "Handle.toText")
(sandbox-builtin "ThreadId.toText")
(sandbox-builtin "IO.socketPort.impl.v3")

View File

@ -6,6 +6,7 @@
unison/data
unison/data-info
unison/chunked-seq
unison/network-utils
unison/core)
(provide
@ -25,29 +26,6 @@
(struct socket-pair (input output))
(define (handle-errors fn)
(with-handlers
[[exn:fail:network?
(lambda (e)
(exception
ref-iofailure:typelink
(exception->string e)
ref-unit-unit))]
[exn:fail:contract?
(lambda (e)
(exception
ref-miscfailure:typelink
(exception->string e)
ref-unit-unit))]
[(lambda _ #t)
(lambda (e)
(exception
ref-miscfailure:typelink
(chunked-string->string
(format "Unknown exception ~a" (exn->string e)))
ref-unit-unit))]]
(fn)))
(define (closeSocket.impl.v3 socket)
(handle-errors
(lambda ()

View File

@ -0,0 +1,179 @@
; UDP primitives!
#lang racket/base
(require racket/udp
racket/format
(only-in unison/boot define-unison)
unison/data
unison/data-info
unison/chunked-seq
(only-in unison/boot sum-case)
unison/network-utils
unison/core)
(provide
(prefix-out
builtin-IO.UDP.
(combine-out
clientSocket.impl.v1
clientSocket.impl.v1:termlink
UDPSocket.recv.impl.v1
UDPSocket.recv.impl.v1:termlink
UDPSocket.send.impl.v1
UDPSocket.send.impl.v1:termlink
UDPSocket.close.impl.v1
UDPSocket.close.impl.v1:termlink
ListenSocket.close.impl.v1
ListenSocket.close.impl.v1:termlink
UDPSocket.toText.impl.v1
UDPSocket.toText.impl.v1:termlink
serverSocket.impl.v1
serverSocket.impl.v1:termlink
ListenSocket.toText.impl.v1
ListenSocket.toText.impl.v1:termlink
ListenSocket.recvFrom.impl.v1
ListenSocket.recvFrom.impl.v1:termlink
ClientSockAddr.toText.v1
ClientSockAddr.toText.v1:termlink
ListenSocket.sendTo.impl.v1
ListenSocket.sendTo.impl.v1:termlink)))
(struct client-sock-addr (host port))
; Haskell's Network.UDP choice of buffer size is 2048, so mirror that here
(define buffer-size 2048)
(define ; a -> Either Failure a
(wrap-in-either a)
(sum-case a
(0 (type msg meta)
(ref-either-left (ref-failure-failure type msg (unison-any-any meta))))
(1 (data)
(ref-either-right data))))
(define
(format-socket socket)
(let*-values ([(local-hn local-port remote-hn remote-port) (udp-addresses socket #t)]
[(rv) (~a "<socket local=" local-hn ":" local-port " remote=" remote-hn ":" remote-port ">")])
(string->chunked-string rv)))
(define (close-socket socket)
(let ([rv (handle-errors (lambda() (begin
(udp-close socket)
(right ref-unit-unit))))])
(wrap-in-either rv)))
;; define termlink builtins
(define clientSocket.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.clientSocket.impl.v1"))
(define UDPSocket.recv.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.UDPSocket.recv.impl.v1"))
(define UDPSocket.send.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.UDPSocket.send.impl.v1"))
(define UDPSocket.close.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.UDPSocket.close.impl.v1"))
(define ListenSocket.close.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.ListenSocket.close.impl.v1"))
(define UDPSocket.toText.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.UDPSocket.toText.impl.v1"))
(define serverSocket.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.serverSocket.impl.v1"))
(define ListenSocket.toText.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.ListenSocket.toText.impl.v1"))
(define ListenSocket.recvFrom.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.ListenSocket.recvFrom.impl.v1"))
(define ClientSockAddr.toText.v1:termlink
(unison-termlink-builtin "IO.UDP.ClientSockAddr.toText.v1"))
(define ListenSocket.sendTo.impl.v1:termlink
(unison-termlink-builtin "IO.UDP.ListenSocket.sendTo.impl.v1"))
;; define builtins
(define-unison
(UDPSocket.recv.impl.v1 socket) ; socket -> Either Failure Bytes
(let
([rv (handle-errors (lambda()
(let*-values
([(buffer) (make-bytes buffer-size)]
[(len a b) (udp-receive! socket buffer)])
(right (bytes->chunked-bytes (subbytes buffer 0 len))))))])
(wrap-in-either rv)))
(define-unison
(ListenSocket.close.impl.v1 socket) ; socket -> Either Failure ()
(close-socket socket))
(define-unison
(serverSocket.impl.v1 ip port) ; string string -> Either Failure socket
(let
([result (handle-errors (lambda()
(let* ([iip (chunked-string->string ip)]
[pport (string->number (chunked-string->string port))]
[sock (udp-open-socket iip pport)])
(begin
(udp-bind! sock iip pport)
(right sock)))))])
(wrap-in-either result)))
(define-unison
(ListenSocket.recvFrom.impl.v1 socket) ; socket -> Either Failure (Bytes, ClientSockAddr)
(let ([result (handle-errors (lambda()
(if (not (udp? socket))
(raise-argument-error 'socket "a UDP socket" socket)
(let*-values
([(buffer) (make-bytes buffer-size)]
[(len host port) (udp-receive! socket buffer)]
[(csa) (client-sock-addr host port)]
[(bs) (subbytes buffer 0 len)]
[(chunked) (bytes->chunked-bytes bs)])
(right (ref-tuple-pair chunked (ref-tuple-pair csa ref-unit-unit)))))))])
(wrap-in-either result)))
(define-unison
(UDPSocket.send.impl.v1 socket data) ; socket -> Bytes -> Either Failure ()
(let
([result (handle-errors (lambda () (begin
(udp-send socket (chunked-bytes->bytes data))
(right ref-unit-unit))))])
(wrap-in-either result)))
(define-unison
(ListenSocket.sendTo.impl.v1 sock bytes addr) ; socket -> Bytes -> ClientSockAddr -> Either Failure ()
(let
([result (handle-errors (lambda()
(let* ([host (client-sock-addr-host addr)]
[port (client-sock-addr-port addr)]
[bytes (chunked-bytes->bytes bytes)])
(begin
(udp-send-to sock host port bytes)
(right ref-unit-unit)))))])
(wrap-in-either result)))
(define-unison
(UDPSocket.toText.impl.v1 socket) ; socket -> string
(format-socket socket))
(define-unison
(ClientSockAddr.toText.v1 addr) ; ClientSocketAddr -> string
(string->chunked-string (format "<client-sock-addr ~a ~a>" (client-sock-addr-host addr) (client-sock-addr-port addr))))
(define-unison
(ListenSocket.toText.impl.v1 socket) ; socket -> string
(format-socket socket))
(define-unison
(UDPSocket.close.impl.v1 socket) ; socket -> Either Failure ()
(let
([rv (handle-errors (lambda() (begin
(udp-close socket)
(right ref-unit-unit))))])
(wrap-in-either rv)))
(define-unison
(clientSocket.impl.v1 host port) ; string string -> Either Failure socket
(let ([rv (handle-errors (lambda() (let* ([pport (string->number (chunked-string->string port))]
[hhost (chunked-string->string host)]
[sock (udp-open-socket hhost pport)]
[_ (udp-bind! sock #f 0)]
[res (udp-connect! sock hhost pport)]) (right sock))))])
(wrap-in-either rv)))

View File

@ -65,6 +65,7 @@ extra-deps:
- lsp-2.2.0.0@sha256:82fbf4b69d94d8d22543be71f89986b3e90050032d671fb3de3f8253ea1e5b6f,3550
- lsp-types-2.0.2.0@sha256:a9a51c3cea0726d91fe63fa0670935ee720f7b31bc3f3b33b2483fc538152677,29421
- row-types-1.0.1.2@sha256:4d4c7cb95d06a32b28ba977852d52a26b4c1f695ef083a6fd874ab6d79933b64,3071
- network-udp-0.0.0
ghc-options:
# All packages

View File

@ -82,6 +82,13 @@ packages:
size: 1060
original:
hackage: row-types-1.0.1.2@sha256:4d4c7cb95d06a32b28ba977852d52a26b4c1f695ef083a6fd874ab6d79933b64,3071
- completed:
hackage: network-udp-0.0.0@sha256:408d2d4fa1a25e49e95752ee124cca641993404bb133ae10fb81daef22d876ae,1075
pantry-tree:
sha256: ee19a66c9d420861c5cc1dfad3210e2a53cdc6088ff3dd90b44f7961f5caebee
size: 284
original:
hackage: network-udp-0.0.0
snapshots:
- completed:
sha256: 5a59b2a405b3aba3c00188453be172b85893cab8ebc352b1ef58b0eae5d248a2

View File

@ -50,6 +50,7 @@ dependencies:
- mtl
- network-uri
- network-simple
- network-udp
- network
- co-log-core
- uri-encode

View File

@ -215,6 +215,7 @@ library
, mtl
, network
, network-simple
, network-udp
, network-uri
, nonempty-containers
, open-browser
@ -353,6 +354,7 @@ executable transcripts
, mtl
, network
, network-simple
, network-udp
, network-uri
, nonempty-containers
, open-browser
@ -499,6 +501,7 @@ test-suite cli-tests
, mtl
, network
, network-simple
, network-udp
, network-uri
, nonempty-containers
, open-browser

View File

@ -15,6 +15,19 @@ import Unison.LabeledDependency qualified as LD
import Unison.Name qualified as Name
import Unison.Names.ResolutionResult qualified as Names
import Unison.Prelude
( Const (Const, getConst),
Generic,
Generic1,
Identity (runIdentity),
Map,
Set,
Text,
foldl',
join,
sortOn,
($>),
(<&>),
)
import Unison.Reference (TypeReference)
import Unison.Reference qualified as Reference
import Unison.Settings qualified as Settings
@ -269,6 +282,11 @@ filePathRef = Reference.Builtin "FilePath"
threadIdRef = Reference.Builtin "ThreadId"
socketRef = Reference.Builtin "Socket"
udpSocketRef, udpListenSocketRef, udpClientSockAddrRef :: TypeReference
udpSocketRef = Reference.Builtin "UDPSocket"
udpListenSocketRef = Reference.Builtin "ListenSocket"
udpClientSockAddrRef = Reference.Builtin "ClientSockAddr"
processHandleRef :: TypeReference
processHandleRef = Reference.Builtin "ProcessHandle"
@ -388,6 +406,15 @@ mbytearrayType a = ref a mbytearrayRef
socket :: (Ord v) => a -> Type v a
socket a = ref a socketRef
udpSocket :: (Ord v) => a -> Type v a
udpSocket a = ref a udpSocketRef
udpListenSocket :: (Ord v) => a -> Type v a
udpListenSocket a = ref a udpListenSocketRef
udpClientSockAddr :: (Ord v) => a -> Type v a
udpClientSockAddr a = ref a udpClientSockAddrRef
list :: (Ord v) => a -> Type v a
list a = ref a listRef

View File

@ -0,0 +1,66 @@
UDP.client' h p = Either.toException (##IO.UDP.clientSocket.impl.v1 h p)
UDP.server' i p = Either.toException (##IO.UDP.serverSocket.impl.v1 i p)
closeClient' = ##IO.UDP.UDPSocket.close.impl.v1 >> Either.toException
send' s b = Either.toException (##IO.UDP.UDPSocket.send.impl.v1 s b)
closeServer' = ##IO.UDP.ListenSocket.close.impl.v1 >> Either.toException
sendTo' s b a = Either.toException (##IO.UDP.ListenSocket.sendTo.impl.v1 s b a)
recvFrom' = ##IO.UDP.ListenSocket.recvFrom.impl.v1 >> Either.toException
recv' = ##IO.UDP.UDPSocket.recv.impl.v1 >> Either.toException
badPort = "what"
badIp = "what"
goodPort = "8000"
goodIp = "127.0.0.1"
shouldFail fn =
result = catchAll fn
isLeft result
udp.tests = do
check "client rejects invalid port" do shouldFail do UDP.client' goodIp badPort
check "server rejects invalid port" do shouldFail do UDP.server' goodIp badPort
check "server rejects invalid IP address" do shouldFail do UDP.server' badIp goodPort
check "client: no send after close" do shouldFail do
socket = UDP.client' goodIp goodPort
closeClient' socket
send' socket (toUtf8 "hello") -- should fail here
check "server no send after close" do shouldFail do
ssocket = UDP.server' goodIp goodPort
csocket = UDP.client' goodIp goodPort
send' csocket (toUtf8 "hello")
(_, clientSockAddr) = recvFrom' ssocket
closeServer' ssocket
sendTo' ssocket (toUtf8 "hello") clientSockAddr -- should fail here
check "no receive after close" do shouldFail do
socket = UDP.client' goodIp goodPort
closeClient' socket
recv' socket
!testServerAndClient
testServerAndClient = do
fromServerMsg = "from server"
fromClientMsg = "from client"
setup = catchAll do
UDP.server' goodIp goodPort
match setup with
Left e ->
Tests.fail "Unable to open a socket for UDP server" (Debug.evalToText e)
Right ssocket ->
serve = do
(data, sockAddr) = recvFrom' ssocket
sendTo' ssocket (toUtf8 fromServerMsg) sockAddr
closeServer' ssocket
fromUtf8 data
serveResult = !Promise.new
_ = fork do Promise.write serveResult (catchAll serve)
data = catchAll do
csocket = UDP.client' goodIp goodPort
send' csocket (toUtf8 fromClientMsg)
d = recv' csocket
closeClient' csocket
fromUtf8 d
checkEqual "Server received data" (Promise.read serveResult) (Right fromClientMsg)
checkEqual "Client received data" data (Right fromServerMsg)

File diff suppressed because it is too large Load Diff

View File

@ -178,21 +178,21 @@ Stream.collect s =
handle !s with Stream.collect.handler
-- An ability that facilitates creating temoporary directories that can be
-- An ability that facilitates creating temoporary directories that can be
-- automatically cleaned up
structural ability TempDirs where
newTempDir: Text -> Text
removeDir: Text -> ()
-- A handler for TempDirs which cleans up temporary directories
-- This will be useful for IO tests which need to interact with
-- This will be useful for IO tests which need to interact with
-- the filesystem
autoCleaned.handler: '{io2.IO} (Request {TempDirs} r -> r)
autoCleaned.handler _ =
remover : [Text] -> {io2.IO} ()
remover = cases
a +: as -> match removeDirectory.impl a with
a +: as -> match removeDirectory.impl a with
Left (Failure _ e _) -> watch e ()
_ -> ()
remover as
@ -277,12 +277,12 @@ putBytes = compose2 reraise putBytes.impl
getLine = compose reraise getLine.impl
systemTime = compose reraise systemTime.impl
decodeCert = compose reraise decodeCert.impl
serverSocket = compose2 reraise serverSocket.impl
serverSocket = compose2 reraise IO.serverSocket.impl
listen = compose reraise listen.impl
handshake = compose reraise handshake.impl
send = compose2 reraise send.impl
handshake = compose reraise handshake.impl
send = compose2 reraise Tls.send.impl
closeSocket = compose reraise closeSocket.impl
clientSocket = compose2 reraise clientSocket.impl
clientSocket = compose2 reraise IO.clientSocket.impl
receive = compose reraise receive.impl
terminate = compose reraise terminate.impl
newServer = compose2 reraise newServer.impl
@ -451,4 +451,3 @@ saveTestCase name ver f i =
saveSelfContained (f, i) sfile
writeFile ofile (toUtf8 output)
writeFile hfile (Bytes.toBase32 (crypto.hash Sha3_512 (f, i)))

View File

@ -1,9 +1,9 @@
```unison:hide
serverSocket = compose2 reraise serverSocket.impl
serverSocket = compose2 reraise IO.serverSocket.impl
socketPort = compose reraise socketPort.impl
listen = compose reraise listen.impl
closeSocket = compose reraise closeSocket.impl
clientSocket = compose2 reraise clientSocket.impl
clientSocket = compose2 reraise IO.clientSocket.impl
socketSend = compose2 reraise socketSend.impl
socketReceive = compose2 reraise socketReceive.impl
socketAccept = compose reraise socketAccept.impl
@ -36,11 +36,11 @@ stored in `/etc/services` and queried with the `getent` tool:
# map number to name
$ getent services 22
ssh 22/tcp
# map name to number
$ getent services finger
finger 79/tcp
# get a list of all known names
$ getent services | head
tcpmux 1/tcp
@ -58,35 +58,35 @@ Below shows different examples of how we might specify the server coordinates.
``` unison
testExplicitHost : '{io2.IO} [Result]
testExplicitHost _ =
testExplicitHost _ =
test = 'let
sock = serverSocket (Some "127.0.0.1") "1028"
emit (Ok "successfully created socket")
port = socketPort sock
putBytes (stdHandle StdOut) (toUtf8 (toText port))
expectU "should have bound to port 1028" 1028 port
expectU "should have bound to port 1028" 1028 port
runTest test
testDefaultHost : '{io2.IO} [Result]
testDefaultHost _ =
testDefaultHost _ =
test = 'let
sock = serverSocket None "1028"
emit (Ok "successfully created socket")
port = socketPort sock
putBytes (stdHandle StdOut) (toUtf8 (toText port))
expectU "should have bound to port 1028" 1028 port
expectU "should have bound to port 1028" 1028 port
runTest test
testDefaultPort : '{io2.IO} [Result]
testDefaultPort _ =
testDefaultPort _ =
test = 'let
sock = serverSocket None "0"
emit (Ok "successfully created socket")
port = socketPort sock
putBytes (stdHandle StdOut) (toUtf8 (toText port))
check "port should be > 1024" (1024 < port)
check "port should be < 65536" (65536 > port)
@ -113,7 +113,7 @@ serverThread portVar toSend = 'let
socketSend sock' (toUtf8 toSend)
closeSocket sock'
match (toEither go) with
match (toEither go) with
Left (Failure _ t _) -> watch t ()
_ -> ()
@ -130,24 +130,24 @@ clientThread portVar resultVar = 'let
_ -> ()
testTcpConnect : '{io2.IO}[Result]
testTcpConnect = 'let
testTcpConnect = 'let
test = 'let
portVar = !MVar.newEmpty
resultVar = !MVar.newEmpty
toSend = "12345"
void (forkComp (serverThread portVar toSend))
void (forkComp (clientThread portVar resultVar))
received = take resultVar
expectU "should have reaped what we've sown" toSend received
runTest test
```
```ucm
```ucm
.> add
.> io.test testTcpConnect

View File

@ -1,9 +1,9 @@
```unison
serverSocket = compose2 reraise serverSocket.impl
serverSocket = compose2 reraise IO.serverSocket.impl
socketPort = compose reraise socketPort.impl
listen = compose reraise listen.impl
closeSocket = compose reraise closeSocket.impl
clientSocket = compose2 reraise clientSocket.impl
clientSocket = compose2 reraise IO.clientSocket.impl
socketSend = compose2 reraise socketSend.impl
socketReceive = compose2 reraise socketReceive.impl
socketAccept = compose reraise socketAccept.impl
@ -34,11 +34,11 @@ stored in `/etc/services` and queried with the `getent` tool:
# map number to name
$ getent services 22
ssh 22/tcp
# map name to number
$ getent services finger
finger 79/tcp
# get a list of all known names
$ getent services | head
tcpmux 1/tcp
@ -56,35 +56,35 @@ Below shows different examples of how we might specify the server coordinates.
```unison
testExplicitHost : '{io2.IO} [Result]
testExplicitHost _ =
testExplicitHost _ =
test = 'let
sock = serverSocket (Some "127.0.0.1") "1028"
emit (Ok "successfully created socket")
port = socketPort sock
putBytes (stdHandle StdOut) (toUtf8 (toText port))
expectU "should have bound to port 1028" 1028 port
expectU "should have bound to port 1028" 1028 port
runTest test
testDefaultHost : '{io2.IO} [Result]
testDefaultHost _ =
testDefaultHost _ =
test = 'let
sock = serverSocket None "1028"
emit (Ok "successfully created socket")
port = socketPort sock
putBytes (stdHandle StdOut) (toUtf8 (toText port))
expectU "should have bound to port 1028" 1028 port
expectU "should have bound to port 1028" 1028 port
runTest test
testDefaultPort : '{io2.IO} [Result]
testDefaultPort _ =
testDefaultPort _ =
test = 'let
sock = serverSocket None "0"
emit (Ok "successfully created socket")
port = socketPort sock
putBytes (stdHandle StdOut) (toUtf8 (toText port))
check "port should be > 1024" (1024 < port)
check "port should be < 65536" (65536 > port)
@ -143,7 +143,7 @@ serverThread portVar toSend = 'let
socketSend sock' (toUtf8 toSend)
closeSocket sock'
match (toEither go) with
match (toEither go) with
Left (Failure _ t _) -> watch t ()
_ -> ()
@ -160,22 +160,22 @@ clientThread portVar resultVar = 'let
_ -> ()
testTcpConnect : '{io2.IO}[Result]
testTcpConnect = 'let
testTcpConnect = 'let
test = 'let
portVar = !MVar.newEmpty
resultVar = !MVar.newEmpty
toSend = "12345"
void (forkComp (serverThread portVar toSend))
void (forkComp (clientThread portVar resultVar))
received = take resultVar
expectU "should have reaped what we've sown" toSend received
runTest test
```
```ucm

View File

@ -17,74 +17,77 @@ The `builtins.merge` command adds the known builtins to a `builtin` subnamespace
6. Bytes/ (34 terms)
7. Char (builtin type)
8. Char/ (22 terms, 1 type)
9. Code (builtin type)
10. Code/ (9 terms)
11. Debug/ (3 terms)
12. Doc (type)
13. Doc/ (6 terms)
14. Either (type)
15. Either/ (2 terms)
16. Exception (type)
17. Exception/ (1 term)
18. Float (builtin type)
19. Float/ (38 terms)
20. Handle/ (1 term)
21. ImmutableArray (builtin type)
22. ImmutableArray/ (3 terms)
23. ImmutableByteArray (builtin type)
24. ImmutableByteArray/ (8 terms)
25. Int (builtin type)
26. Int/ (31 terms)
27. IsPropagated (type)
28. IsPropagated/ (1 term)
29. IsTest (type)
30. IsTest/ (1 term)
31. Link (type)
32. Link/ (3 terms, 2 types)
33. List (builtin type)
34. List/ (10 terms)
35. MutableArray (builtin type)
36. MutableArray/ (6 terms)
37. MutableByteArray (builtin type)
38. MutableByteArray/ (14 terms)
39. Nat (builtin type)
40. Nat/ (28 terms)
41. Optional (type)
42. Optional/ (2 terms)
43. Pattern (builtin type)
44. Pattern/ (9 terms)
45. Ref (builtin type)
46. Ref/ (2 terms)
47. Request (builtin type)
48. RewriteCase (type)
49. RewriteCase/ (1 term)
50. RewriteSignature (type)
51. RewriteSignature/ (1 term)
52. RewriteTerm (type)
53. RewriteTerm/ (1 term)
54. Rewrites (type)
55. Rewrites/ (1 term)
56. Scope (builtin type)
57. Scope/ (6 terms)
58. SeqView (type)
59. SeqView/ (2 terms)
60. Socket/ (1 term)
61. Test/ (2 terms, 1 type)
62. Text (builtin type)
63. Text/ (34 terms)
64. ThreadId/ (1 term)
65. Tuple (type)
66. Tuple/ (1 term)
67. Unit (type)
68. Unit/ (1 term)
69. Universal/ (7 terms)
70. Value (builtin type)
71. Value/ (5 terms)
72. bug (a -> b)
73. crypto/ (15 terms, 2 types)
74. io2/ (135 terms, 32 types)
75. metadata/ (2 terms)
76. todo (a -> b)
77. unsafe/ (1 term)
9. ClientSockAddr (builtin type)
10. Code (builtin type)
11. Code/ (9 terms)
12. Debug/ (3 terms)
13. Doc (type)
14. Doc/ (6 terms)
15. Either (type)
16. Either/ (2 terms)
17. Exception (type)
18. Exception/ (1 term)
19. Float (builtin type)
20. Float/ (38 terms)
21. Handle/ (1 term)
22. ImmutableArray (builtin type)
23. ImmutableArray/ (3 terms)
24. ImmutableByteArray (builtin type)
25. ImmutableByteArray/ (8 terms)
26. Int (builtin type)
27. Int/ (31 terms)
28. IsPropagated (type)
29. IsPropagated/ (1 term)
30. IsTest (type)
31. IsTest/ (1 term)
32. Link (type)
33. Link/ (3 terms, 2 types)
34. List (builtin type)
35. List/ (10 terms)
36. ListenSocket (builtin type)
37. MutableArray (builtin type)
38. MutableArray/ (6 terms)
39. MutableByteArray (builtin type)
40. MutableByteArray/ (14 terms)
41. Nat (builtin type)
42. Nat/ (28 terms)
43. Optional (type)
44. Optional/ (2 terms)
45. Pattern (builtin type)
46. Pattern/ (9 terms)
47. Ref (builtin type)
48. Ref/ (2 terms)
49. Request (builtin type)
50. RewriteCase (type)
51. RewriteCase/ (1 term)
52. RewriteSignature (type)
53. RewriteSignature/ (1 term)
54. RewriteTerm (type)
55. RewriteTerm/ (1 term)
56. Rewrites (type)
57. Rewrites/ (1 term)
58. Scope (builtin type)
59. Scope/ (6 terms)
60. SeqView (type)
61. SeqView/ (2 terms)
62. Socket/ (1 term)
63. Test/ (2 terms, 1 type)
64. Text (builtin type)
65. Text/ (34 terms)
66. ThreadId/ (1 term)
67. Tuple (type)
68. Tuple/ (1 term)
69. UDPSocket (builtin type)
70. Unit (type)
71. Unit/ (1 term)
72. Universal/ (7 terms)
73. Value (builtin type)
74. Value/ (5 terms)
75. bug (a -> b)
76. crypto/ (15 terms, 2 types)
77. io2/ (146 terms, 32 types)
78. metadata/ (2 terms)
79. todo (a -> b)
80. unsafe/ (1 term)
```

View File

@ -23,7 +23,7 @@ Technically, the definitions all exist, but they have no names. `builtins.merge`
.foo> ls
1. builtin/ (456 terms, 71 types)
1. builtin/ (467 terms, 74 types)
```
And for a limited time, you can get even more builtin goodies:
@ -35,7 +35,7 @@ And for a limited time, you can get even more builtin goodies:
.foo> ls
1. builtin/ (630 terms, 89 types)
1. builtin/ (641 terms, 92 types)
```
More typically, you'd start out by pulling `base.

View File

@ -37,7 +37,7 @@ Exception.unsafeRun! e _ =
socketSend s bytes = reraise (socketSend.impl s bytes)
closeSocket s = reraise (closeSocket.impl s)
serverSocket host port = reraise (serverSocket.impl host port)
serverSocket host port = reraise (IO.serverSocket.impl host port)
hello : Text -> Text -> {IO, Exception} ()
hello host port =

View File

@ -33,7 +33,7 @@ Exception.unsafeRun! e _ =
socketSend s bytes = reraise (socketSend.impl s bytes)
closeSocket s = reraise (closeSocket.impl s)
serverSocket host port = reraise (serverSocket.impl host port)
serverSocket host port = reraise (IO.serverSocket.impl host port)
hello : Text -> Text -> {IO, Exception} ()
hello host port =

View File

@ -119,13 +119,13 @@ it's still in the `history` of the parent namespace and can be resurrected at an
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #mqis95ft23
⊙ 1. #720815367g
- Deletes:
feature1.y
⊙ 2. #5ro9c9692q
⊙ 2. #4hps00eboc
+ Adds / updates:
@ -136,26 +136,26 @@ it's still in the `history` of the parent namespace and can be resurrected at an
Original name New name(s)
feature1.y master.y
⊙ 3. #da33td9rni
⊙ 3. #c15feh0lv3
+ Adds / updates:
feature1.y
⊙ 4. #ks6rftepdv
⊙ 4. #5k00u4h52h
> Moves:
Original name New name
x master.x
⊙ 5. #dgcqc7jftr
⊙ 5. #b3s8tvonc0
+ Adds / updates:
x
□ 6. #ms344fdodl (start of history)
□ 6. #fdbvr2f3s3 (start of history)
```
To resurrect an old version of a namespace, you can learn its hash via the `history` command, then use `fork #namespacehash .newname`.

View File

@ -80,7 +80,7 @@ Should be able to move the term, type, and namespace, including its types, terms
1. Bar (Nat)
2. Bar (type)
3. Bar/ (4 terms, 1 type)
4. builtin/ (456 terms, 71 types)
4. builtin/ (467 terms, 74 types)
.> ls Bar
@ -145,7 +145,7 @@ bonk = 5
.z> ls
1. builtin/ (456 terms, 71 types)
1. builtin/ (467 terms, 74 types)
2. zonk (Nat)
```
@ -188,7 +188,7 @@ bonk.zonk = 5
.a> ls
1. builtin/ (456 terms, 71 types)
1. builtin/ (467 terms, 74 types)
2. zonk/ (1 term)
.a> view zonk.zonk

View File

@ -277,7 +277,7 @@ I should be able to move the root into a sub-namespace
.> ls
1. root/ (1373 terms, 214 types)
1. root/ (1406 terms, 223 types)
.> history
@ -286,22 +286,22 @@ I should be able to move the root into a sub-namespace
□ 1. #vrn80pdffk (start of history)
□ 1. #corns7qr1t (start of history)
```
```ucm
.> ls .root.at.path
1. existing/ (457 terms, 71 types)
2. happy/ (459 terms, 72 types)
3. history/ (457 terms, 71 types)
1. existing/ (468 terms, 74 types)
2. happy/ (470 terms, 75 types)
3. history/ (468 terms, 74 types)
.> history .root.at.path
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #g3ri07hi09
⊙ 1. #vgp4hc72su
- Deletes:
@ -312,7 +312,7 @@ I should be able to move the root into a sub-namespace
Original name New name
existing.a.termInA existing.b.termInA
⊙ 2. #ifjg1bj57v
⊙ 2. #hg5coa0n3k
+ Adds / updates:
@ -324,26 +324,26 @@ I should be able to move the root into a sub-namespace
happy.b.termInA existing.a.termInA
history.b.termInA existing.a.termInA
⊙ 3. #bdn8f7vhg1
⊙ 3. #pgpp3mqenr
+ Adds / updates:
existing.a.termInA existing.b.termInB
⊙ 4. #5dqmgnr0lt
⊙ 4. #gbun790pgn
> Moves:
Original name New name
history.a.termInA history.b.termInA
⊙ 5. #vd3d37rn3c
⊙ 5. #ljad7emlrb
- Deletes:
history.b.termInB
⊙ 6. #gi32sh566a
⊙ 6. #3easopbtbb
+ Adds / updates:
@ -354,13 +354,13 @@ I should be able to move the root into a sub-namespace
Original name New name(s)
happy.b.termInA history.a.termInA
⊙ 7. #u2bs53f2hl
⊙ 7. #bhmp53toom
+ Adds / updates:
history.a.termInA history.b.termInB
⊙ 8. #48hsm89mgl
⊙ 8. #l5ncvimoh2
> Moves:
@ -370,7 +370,7 @@ I should be able to move the root into a sub-namespace
happy.a.T.T2 happy.b.T.T2
happy.a.termInA happy.b.termInA
⊙ 9. #pqd79g3q7l
⊙ 9. #j0hfgeiitb
+ Adds / updates:
@ -380,7 +380,7 @@ I should be able to move the root into a sub-namespace
happy.a.T.T
⊙ 10. #allrjqq7ga
⊙ 10. #7mnjol2gir
+ Adds / updates:
@ -392,7 +392,7 @@ I should be able to move the root into a sub-namespace
⊙ 11. #ohd0a9rim1
⊙ 11. #plq3nk8j34
```
@ -414,26 +414,26 @@ I should be able to move a sub namespace _over_ the root.
.> ls
1. b/ (3 terms, 1 type)
2. builtin/ (456 terms, 71 types)
2. builtin/ (467 terms, 74 types)
.> history
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #lf3m1s2e7i
⊙ 1. #li00cqteoe
+ Adds / updates:
b.T b.T.T1 b.T.T2 b.termInA
⊙ 2. #b1cg22v7s1
⊙ 2. #ck551mk9b5
- Deletes:
a.T a.T.T1 a.T.T2 a.termInA
⊙ 3. #r83v608ifd
⊙ 3. #gearhpa349
+ Adds / updates:
@ -443,13 +443,13 @@ I should be able to move a sub namespace _over_ the root.
a.T.T
⊙ 4. #pmm6a0f6fj
⊙ 4. #f1f560n79b
+ Adds / updates:
a.T a.T.T a.termInA
□ 5. #nmcjvlnbk1 (start of history)
□ 5. #9vjjqeod4l (start of history)
```
```ucm

View File

@ -63,17 +63,17 @@ y = 2
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #mq4oqhiuuq .old` to make an old namespace
`fork #ce6qpkdjhn .old` to make an old namespace
accessible again,
`reset-root #mq4oqhiuuq` to reset the root namespace and
`reset-root #ce6qpkdjhn` to reset the root namespace and
its history to that of the
specified namespace.
When Root Hash Action
1. now #1n5tjujeu7 add
2. now #mq4oqhiuuq add
3. now #nmcjvlnbk1 builtins.merge
1. now #fmdokt2dim add
2. now #ce6qpkdjhn add
3. now #9vjjqeod4l builtins.merge
4. #sg60bvjo91 history starts here
Tip: Use `diff.namespace 1 7` to compare namespaces between

View File

@ -28,13 +28,13 @@ a = 5
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #0nv4t3770d
⊙ 1. #5qd3km7th4
+ Adds / updates:
a
□ 2. #nmcjvlnbk1 (start of history)
□ 2. #9vjjqeod4l (start of history)
.> reset 2
@ -47,7 +47,7 @@ a = 5
□ 1. #nmcjvlnbk1 (start of history)
□ 1. #9vjjqeod4l (start of history)
```
```unison
@ -83,13 +83,13 @@ foo.a = 5
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #3s91aop8k9
⊙ 1. #1p2akhggkc
+ Adds / updates:
foo.a
□ 2. #nmcjvlnbk1 (start of history)
□ 2. #9vjjqeod4l (start of history)
.> reset 1 foo

View File

@ -13,7 +13,7 @@ Let's look at some examples. We'll start with a namespace with just the builtins
□ 1. #3pq2vvggng (start of history)
□ 1. #o6oig4fk7p (start of history)
.> fork builtin builtin2
@ -42,21 +42,21 @@ Now suppose we `fork` a copy of builtin, then rename `Nat.+` to `frobnicate`, th
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #4g884gq7lc
⊙ 1. #695699eqes
> Moves:
Original name New name
Nat.frobnicate Nat.+
⊙ 2. #hnah4l7s0j
⊙ 2. #5acatj352b
> Moves:
Original name New name
Nat.+ Nat.frobnicate
□ 3. #3pq2vvggng (start of history)
□ 3. #o6oig4fk7p (start of history)
```
If we merge that back into `builtin`, we get that same chain of history:
@ -73,21 +73,21 @@ If we merge that back into `builtin`, we get that same chain of history:
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #4g884gq7lc
⊙ 1. #695699eqes
> Moves:
Original name New name
Nat.frobnicate Nat.+
⊙ 2. #hnah4l7s0j
⊙ 2. #5acatj352b
> Moves:
Original name New name
Nat.+ Nat.frobnicate
□ 3. #3pq2vvggng (start of history)
□ 3. #o6oig4fk7p (start of history)
```
Let's try again, but using a `merge.squash` (or just `squash`) instead. The history will be unchanged:
@ -108,7 +108,7 @@ Let's try again, but using a `merge.squash` (or just `squash`) instead. The hist
□ 1. #3pq2vvggng (start of history)
□ 1. #o6oig4fk7p (start of history)
```
The churn that happened in `mybuiltin` namespace ended up back in the same spot, so the squash merge of that namespace with our original namespace had no effect.
@ -493,13 +493,13 @@ This checks to see that squashing correctly preserves deletions:
Note: The most recent namespace hash is immediately below this
message.
⊙ 1. #jdptkosbfp
⊙ 1. #erp3nu5u70
- Deletes:
Nat.* Nat.+
□ 2. #3pq2vvggng (start of history)
□ 2. #o6oig4fk7p (start of history)
```
Notice that `Nat.+` and `Nat.*` are deleted by the squash, and we see them deleted in one atomic step in the history.

View File

@ -57,7 +57,7 @@ proj/main> upgrade old new
proj/main> ls lib
1. builtin/ (456 terms, 71 types)
1. builtin/ (467 terms, 74 types)
2. new/ (1 term)
proj/main> view thingy