Skip to content

Commit b830d58

Browse files
committed
Fix #96, #99, Support socket for Blodwen
1 parent f262d3b commit b830d58

File tree

23 files changed

+1009
-193
lines changed

23 files changed

+1009
-193
lines changed

idris-jvm-core/src/main/idris/IdrisJvm/Core/Foreign.idr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ mutual
6161
fdescFieldDescriptor (FCon "JVM_Bool") = FieldTyDescBoolean
6262

6363
fdescFieldDescriptor (FCon "JVM_Str") = FieldTyDescReference $ ClassDesc "java/lang/String"
64+
fdescFieldDescriptor (FCon "JVM_BigInteger") = FieldTyDescReference $ ClassDesc "java/math/BigInteger"
6465
fdescFieldDescriptor fdesc = FieldTyDescReference $ fdescRefDescriptor fdesc
6566

6667
fdescRefDescriptor : FDesc -> ReferenceTypeDescriptor
@@ -73,6 +74,7 @@ mutual
7374
fdescRefDescriptor desc@(FApp "JVM_Nullable" [FApp "Interface" [FStr typeName]]) = NullableRefDesc typeName
7475

7576
fdescRefDescriptor (FCon "JVM_Str") = ClassDesc "java/lang/String"
77+
fdescRefDescriptor (FCon "JVM_BigInteger") = ClassDesc "java/math/BigInteger"
7678
fdescRefDescriptor (FStr exportedType) = IdrisExportDesc exportedType
7779
fdescRefDescriptor (FCon "JVM_NullableStr") = NullableStrDesc
7880
fdescRefDescriptor desc = jerror $ "Invalid reference type descriptor: " ++ show desc

idris-jvm-ffi/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,14 @@
5454
</executions>
5555
</plugin>
5656
</plugins>
57+
5758
</build>
59+
60+
<dependencies>
61+
<dependency>
62+
<groupId>io.github.mmhelloworld</groupId>
63+
<artifactId>idris-jvm-io</artifactId>
64+
<version>1.0-SNAPSHOT</version>
65+
</dependency>
66+
</dependencies>
5867
</project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
module IdrisJvm.ClientServerSocket
2+
3+
import IdrisJvm.IO
4+
import Java.Nio
5+
6+
%access public export
7+
8+
namespace ClientServerSocket
9+
ClientServerSocketClass : JVM_NativeTy
10+
ClientServerSocketClass = Class "io/github/mmhelloworld/idrisjvm/io/ClientServerSocket"
11+
12+
ClientServerSocket : Type
13+
ClientServerSocket = JVM_Native ClientServerSocketClass
14+
15+
listenAndAccept : Int -> JVM_IO (Either Throwable ClientServerSocket)
16+
listenAndAccept =
17+
invokeStatic ClientServerSocketClass "listenAndAccept" (Int -> JVM_IO (Either Throwable ClientServerSocket))
18+
19+
getChar : ClientServerSocket -> JVM_IO Char
20+
getChar = invokeInstance "getChar" (ClientServerSocket -> JVM_IO Char)
21+
22+
getLine : ClientServerSocket -> JVM_IO String
23+
getLine = invokeInstance "getLine" (ClientServerSocket -> JVM_IO String)
24+
25+
writeString : ClientServerSocket -> String -> JVM_IO ()
26+
writeString = invokeInstance "writeString" (ClientServerSocket -> String -> JVM_IO ())
27+
28+
close : ClientServerSocket -> JVM_IO ()
29+
close = invokeInstance "close" (ClientServerSocket -> JVM_IO ())
30+
31+
Inherits Channel ClientServerSocket where {}
32+
Inherits ReadableByteChannel ClientServerSocket where {}
33+
Inherits WritableByteChannel ClientServerSocket where {}
34+

idris-jvm-ffi/src/main/idris/IdrisJvm/Data/Buffer.idr

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module IdrisJvm.Data.Buffer
33
import IdrisJvm.IO
44
import IdrisJvm.File
55
import Java.Nio
6+
import IdrisJvm.FileChannelIo
7+
import IdrisJvm.ClientServerSocket
68

79
%hide Prelude.File.File
810

@@ -121,28 +123,42 @@ export
121123
getString : Buffer -> (loc : Int) -> (len : Int) -> JVM_IO String
122124
getString b loc len = invokeInstance "getString" (IdrisBuffer -> Int -> Int -> JVM_IO String) (rawdata b) loc len
123125

126+
export
127+
readBufferFromReadableByteChannel :
128+
Inherits ReadableByteChannel channel => channel -> Buffer -> (maxbytes : Int) -> JVM_IO Buffer
129+
readBufferFromReadableByteChannel channel buf max = do
130+
numread <- invokeInstance "readFromFile" (IdrisBuffer -> ReadableByteChannel -> Int -> Int -> JVM_IO Int)
131+
(rawdata buf) (believe_me channel) (location buf) max
132+
pure (record { location $= (+numread) } buf)
133+
134+
export
135+
writeBufferToWritableByteChannel :
136+
Inherits WritableByteChannel channel => channel -> Buffer -> (maxbytes : Int) -> JVM_IO Buffer
137+
writeBufferToWritableByteChannel channel buf max = do
138+
let maxwrite = size buf - location buf
139+
let max' = if maxwrite < max then maxwrite else max
140+
invokeInstance "writeToFile" (IdrisBuffer -> WritableByteChannel -> Int -> Int -> JVM_IO ())
141+
(rawdata buf) (believe_me channel) (location buf) max'
142+
pure (record { location $= (+max') } buf)
143+
124144
||| Read 'maxbytes' into the buffer from a file, returning a new
125145
||| buffer with the 'locaton' pointer moved along
126146
export
127147
total
128148
readBufferFromFile : File -> Buffer -> (maxbytes : Int) -> JVM_IO Buffer
129-
readBufferFromFile (MkFile file path) buf max = do
130-
numread <- invokeInstance "readFromFile" (IdrisBuffer -> FileChannel -> Int -> Int -> JVM_IO Int)
131-
(rawdata buf) file (location buf) max
132-
pure (record { location $= (+numread) } buf)
149+
readBufferFromFile (MkFile fileChannelIo) buf max =
150+
readBufferFromReadableByteChannel fileChannelIo buf max
151+
readBufferFromFile (MkFileClientServerSocket clientServerSocket) buf max =
152+
readBufferFromReadableByteChannel clientServerSocket buf max
133153
readBufferFromFile _ buf max = pure buf
134154

135155
||| Write 'maxbytes' from the buffer from a file, returning a new
136156
||| buffer with the 'location' pointer moved along
137157
export
138158
total
139159
writeBufferToFile : File -> Buffer -> (maxbytes : Int) -> JVM_IO Buffer
140-
writeBufferToFile (MkFile file path) buf max
141-
= do let maxwrite = size buf - location buf
142-
let max' = if maxwrite < max then maxwrite else max
143-
invokeInstance "writeToFile" (IdrisBuffer -> FileChannel -> Int -> Int -> JVM_IO ())
144-
(rawdata buf) file (location buf) max'
145-
pure (record { location $= (+max') } buf)
160+
writeBufferToFile (MkFile channel) buf max = writeBufferToWritableByteChannel channel buf max
161+
writeBufferToFile (MkFileClientServerSocket channel) buf max = writeBufferToWritableByteChannel channel buf max
146162
writeBufferToFile _ buf max = pure buf
147163

148164
||| Return the contents of the buffer as a list

idris-jvm-ffi/src/main/idris/IdrisJvm/FFI.idr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ mutual
9090
JVM_Str : JVM_Types String
9191
JVM_Double : JVM_Types Double
9292
JVM_Float : JVM_Types JFloat
93+
JVM_BigInteger : JVM_Types Integer
9394
JVM_Unit : JVM_Types ()
9495
JVM_NullableStr : JVM_Types (Maybe String)
9596
JVM_Nullable : JVM_Types (Maybe (JVM_Native t))
@@ -164,6 +165,8 @@ namespace Object
164165
Inherits Object String where {}
165166
Inherits Object (Maybe String) where {}
166167

168+
Inherits Object Integer where {}
169+
167170
Inherits Object (JVM_Native t) where {}
168171
Inherits Object (Maybe (JVM_Native t)) where {}
169172

idris-jvm-ffi/src/main/idris/IdrisJvm/File.idr

Lines changed: 62 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,21 @@ import Java.Nio
99
import Java.IO
1010
import Java.Util
1111
import Java.Util.Concurrent
12-
13-
%language TypeProviders
14-
%language ElabReflection
12+
import IdrisJvm.ClientServerSocket
13+
import IdrisJvm.FileChannelIo
14+
import IdrisJvm.Files
15+
import IdrisJvm.System
1516

1617
%hide Prelude.File.File
1718
%hide Prelude.File.FileError
1819
%hide Java.IO.File.File
1920

20-
jdkimport [
21-
(stringClass, ["getBytes"]),
22-
(pathsClass, ["get"]),
23-
(fileChannelClass, ["open"]),
24-
(filesClass, ["lines", "write", "readAttributes", "createDirectory"]),
25-
(fileTimeClass, ["to"]),
26-
(streamClass, ["collect"]),
27-
(collectorsClass, ["joining"])
28-
]
29-
3021
public export
3122
data File = MkFileStdin
3223
| MkFileStdout
3324
| MkFileStderr
34-
| MkFile FileChannel Path
25+
| MkFile FileChannelIo
26+
| MkFileClientServerSocket ClientServerSocket
3527

3628
public export
3729
FileError : Type
@@ -68,14 +60,13 @@ export
6860
total
6961
openFile : (f : String) -> (m : Mode) -> JVM_IO (Either FileError File)
7062
openFile f m = assert_total $ do
71-
path <- invokeStatic RuntimeClass "createPath" (String -> JVM_IO Path) f
63+
path <- Files.createPath f
7264
ensureParentDir path
7365
openOptions <- listToArray (modeToOpenOption m)
74-
exceptionOrFile <- (fileChannelClass <.> "open(java/nio/file/Path,Array 1 i java/nio/file/OpenOption)") path openOptions
66+
exceptionOrFile <- FileChannelIo.open path openOptions
7567
case exceptionOrFile of
7668
Left exception => pure $ Left $ believe_me exception
77-
Right Nothing => pure $ Left . believe_me $ !(unableToOpenFile f)
78-
Right (Just file) => pure $ Right (MkFile file path)
69+
Right file => pure $ Right (MkFile file)
7970
where
8071
hasWriteMode : Bool
8172
hasWriteMode = case m of
@@ -91,54 +82,75 @@ openFile f m = assert_total $ do
9182
case optParent of
9283
Nothing => pure ()
9384
Just pathDir => do
94-
_ <- invokeStatic FilesClass "createDirectories" (Path -> JVM_Array FileAttribute -> JVM_IO Path) pathDir
95-
!(newArray FileAttribute 0)
85+
Files.createDirectories pathDir
9686
pure ()
9787
else pure ()
88+
export
89+
getChar : File -> JVM_IO Char
90+
getChar (MkFile fileChannelIo) = getChar fileChannelIo
91+
getChar (MkFileClientServerSocket clientServerSocket) = getChar clientServerSocket
92+
getChar MkFileStdin = IO.getChar
93+
getChar _ = do
94+
putStrLn "Unable to read a character"
95+
exit 1
96+
97+
export
98+
getLine : File -> JVM_IO String
99+
getLine (MkFile fileChannelIo) = getLine fileChannelIo
100+
getLine (MkFileClientServerSocket clientServerSocket) = ClientServerSocket.getLine clientServerSocket
101+
getLine MkFileStdin = IO.getLine
102+
getLine _ = do
103+
putStrLn "Unable to read a line"
104+
exit 1
105+
106+
export
107+
writeString : File -> String -> JVM_IO ()
108+
writeString (MkFile fileChannelIo) str = writeString fileChannelIo str
109+
writeString (MkFileClientServerSocket socket) str = writeString socket str
110+
writeString MkFileStdout str = print str
111+
writeString _ _ = pure ()
98112

99113
export
100114
closeFile : File -> JVM_IO ()
101-
closeFile (MkFile file _) = Channel.close file
115+
closeFile (MkFile file) = FileChannelIo.close file
116+
closeFile (MkFileClientServerSocket clientServerSocket) = ClientServerSocket.close clientServerSocket
102117
closeFile _ = pure ()
103118

104119
export
105120
changeDir : String -> JVM_IO Bool
106-
changeDir = invokeStatic RuntimeClass "changeDir" (String -> JVM_IO Bool)
121+
changeDir = Files.changeDir
107122

108123
export
109124
getTemporaryFileName : JVM_IO String
110-
getTemporaryFileName = invokeStatic RuntimeClass "getTemporaryFileName" (JVM_IO String)
125+
getTemporaryFileName = Files.getTemporaryFileName
111126

112127
export
113128
chmod : String -> Int -> JVM_IO ()
114-
chmod f m = invokeStatic RuntimeClass "chmod" (String -> Int -> JVM_IO ()) f m
129+
chmod = Files.chmod
115130

116131
export
117132
total
118133
createDir : String -> JVM_IO (Either FileError ())
119-
createDir d = assert_total $ do
120-
path <- invokeStatic RuntimeClass "createPath" (String -> JVM_IO Path) d
121-
exceptionOrPath <- (filesClass <.> "createDirectory") path !(newArray FileAttribute 0)
122-
pure $ const () <$> exceptionOrPath
134+
createDir d = assert_total $ Files.createDirectory d
123135

124136
export
125137
currentDir : JVM_IO String
126-
currentDir = invokeStatic RuntimeClass "getWorkingDir" (JVM_IO String)
138+
currentDir = Files.getWorkingDir
127139

128140
-- This is returning Int to conform to Idris fileSize function type
129141
-- even though Java's FileChannel returns long
130142
export
131143
fileSize : File -> JVM_IO (Either FileError Int)
132-
fileSize (MkFile f _) = do
133-
exceptionOrSize <- invokeInstance "size" (FileChannel -> JVM_IO (JVM_Throwable Bits64)) f
144+
fileSize (MkFile f) = do
145+
exceptionOrSize <- FileChannelIo.size f
134146
case exceptionOrSize of
135147
Left exception => pure $ Left $ believe_me exception
136148
Right size => pure $ Right $ Long.intValue size
137-
fileSize _ = pure . Left . believe_me $ !(IOException.new "Cannot determine size for stdin/stdout/stderr")
149+
fileSize _ = pure . Left . believe_me $ !(IOException.new "Cannot determine size")
138150

139151
export
140152
fflush : File -> JVM_IO ()
141-
fflush (MkFile file _) = invokeInstance "force" (FileChannel -> Bool -> JVM_IO ()) file True
153+
fflush (MkFile file) = FileChannelIo.flush file
142154
fflush MkFileStdout = invokeStatic RuntimeClass "flushStdout" (JVM_IO ())
143155
fflush MkFileStderr = invokeStatic RuntimeClass "flushStderr" (JVM_IO ())
144156
fflush _ = pure ()
@@ -161,61 +173,38 @@ stderr = MkFileStderr
161173
export
162174
total
163175
readFile : String -> JVM_IO (Either FileError String)
164-
readFile pathStr = assert_total $ do
165-
path <- invokeStatic RuntimeClass "createPath" (String -> JVM_IO Path) pathStr
166-
exceptionOrlines <- (filesClass <.> "lines(java/nio/file/Path)") path
167-
case exceptionOrlines of
168-
Left exception => pure $ Left exception
169-
Right Nothing => pure $ Left . believe_me $ !(unableToReadFile pathStr)
170-
Right (Just lines) => do
171-
joiningCollector <- (collectorsClass <.!> "joining(java/lang/CharSequence)") $ believe_me !(lineSeparator)
172-
pure . Right $ believe_me !((streamClass <.!> "collect(java/util/stream/Collector)") lines joiningCollector)
176+
readFile pathStr = assert_total $ Files.readFile pathStr
173177

174178
export
175179
writeFile : String -> String -> JVM_IO (Either FileError ())
176-
writeFile file content = do
177-
path <- invokeStatic RuntimeClass "createPath" (String -> JVM_IO Path) file
178-
bytes <- (stringClass <.!> "getBytes(java/lang/String)") content "UTF-8"
179-
exceptionOrPath <- (filesClass <.> "write(java/nio/file/Path,Array 1 byte,Array 1 i java/nio/file/OpenOption)") path
180-
bytes !(newArray OpenOption 0)
181-
pure $ either (const . Left . believe_me $ !(unableToWriteFile file)) (const $ Right ()) exceptionOrPath
180+
writeFile file content = Files.writeFile file content
182181

183182
export
184183
fileModifiedTime : File -> JVM_IO (Either FileError Integer)
185-
fileModifiedTime (MkFile _ path) = do
186-
attrs <- (filesClass <.!> "readAttributes(java/nio/file/Path,java/lang/Class,Array 1 java/nio/file/LinkOption)")
187-
path (classLit basicFileAttributesClass) !(newArray LinkOption 0)
188-
fileTime <- invokeInstance "lastModifiedTime" (BasicFileAttributes -> JVM_IO FileTime) attrs
189-
seconds <- (fileTimeClass <.!> "to") fileTime TimeUnit.seconds
190-
pure . Right $ believe_me $ BigInteger.valueOf seconds
191-
fileModifiedTime _ = pure . Left $ believe_me !(IOException.new "Cannot get file modified time for stdin, stdout or stderr")
184+
fileModifiedTime (MkFile file) = FileChannelIo.getFileModifiedTime file
185+
fileModifiedTime _ = pure . Left $ believe_me !(IOException.new "Cannot get file modified time")
192186

193187
export
194188
fileAccessTime : File -> JVM_IO (Either FileError Integer)
195-
fileAccessTime (MkFile _ path) = do
196-
attrs <- (filesClass <.!> "readAttributes(java/nio/file/Path,java/lang/Class,Array 1 java/nio/file/LinkOption)")
197-
path (classLit basicFileAttributesClass) !(newArray LinkOption 0)
198-
fileTime <- invokeInstance "lastAccessTime" (BasicFileAttributes -> JVM_IO FileTime) attrs
199-
seconds <- (fileTimeClass <.!> "to") fileTime TimeUnit.seconds
200-
pure . Right $ believe_me $ BigInteger.valueOf seconds
201-
fileAccessTime _ = pure . Left $ believe_me !(IOException.new "Cannot get file access time for stdin, stdout or stderr")
189+
fileAccessTime (MkFile file) = FileChannelIo.getFileAccessTime file
190+
fileAccessTime _ = pure . Left $ believe_me !(IOException.new "Cannot get file access time")
202191

203192
export
204193
fileStatusTime : File -> JVM_IO (Either FileError Integer)
205-
fileStatusTime (MkFile _ path) = do
206-
attrs <- (filesClass <.!> "readAttributes(java/nio/file/Path,java/lang/Class,Array 1 java/nio/file/LinkOption)")
207-
path (classLit basicFileAttributesClass) !(newArray LinkOption 0)
208-
fileTime <- invokeInstance "creationTime" (BasicFileAttributes -> JVM_IO FileTime) attrs
209-
seconds <- (fileTimeClass <.!> "to") fileTime TimeUnit.seconds
210-
pure . Right $ believe_me $ BigInteger.valueOf seconds
211-
fileStatusTime _ = pure . Left $ believe_me !(IOException.new "Cannot get file status time for stdin, stdout or stderr")
194+
fileStatusTime (MkFile file) = FileChannelIo.getFileStatusTime file
195+
fileStatusTime _ = pure . Left $ believe_me !(IOException.new "Cannot get file status time")
212196

213197
||| Check if a file handle has reached the end
214198
export
215199
fEOF : File -> JVM_IO Bool
216-
fEOF (MkFile file _) = do
217-
position <- invokeInstance "position" (FileChannel -> JVM_IO Bits64) file
218-
size <- invokeInstance "size" (FileChannel -> JVM_IO Bits64) file
219-
pure (position == size)
200+
fEOF (MkFile file) = FileChannelIo.isEof file
220201
fEOF MkFileStdin = invokeStatic RuntimeClass "isStdinEof" (JVM_IO Bool)
221202
fEOF _ = pure False
203+
204+
export
205+
socketListenAndAccept : Int -> JVM_IO (Either String File)
206+
socketListenAndAccept port = do
207+
byteBufferIoOrError <- ClientServerSocket.listenAndAccept port
208+
case byteBufferIoOrError of
209+
Left throwable => Left <$> Objects.toString throwable
210+
Right byteBufferIo => pure . Right $ MkFileClientServerSocket byteBufferIo

0 commit comments

Comments
 (0)