Skip to content

Commit

Permalink
ch07 deduped more code
Browse files Browse the repository at this point in the history
  • Loading branch information
spamegg1 committed Apr 10, 2024
1 parent 889400d commit 5196ea9
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 199 deletions.
3 changes: 1 addition & 2 deletions src/main/scala/ch07/curlAsync/loop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ package curlAsync
import scalanative.unsafe.*
import scalanative.libc.stdlib
import collection.mutable.ListBuffer
import concurrent.{ExecutionContext, ExecutionContextExecutor}
import concurrent.{Future, Promise}
import concurrent.{ExecutionContext, ExecutionContextExecutor, Future, Promise}
import util.{Try, Success}

object EventLoop extends ExecutionContextExecutor:
Expand Down
184 changes: 3 additions & 181 deletions src/main/scala/ch07/curlSync/loop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@ package curlSync
import scalanative.unsafe.*
import scalanative.libc.stdlib
import collection.mutable.ListBuffer
import concurrent.{ExecutionContext, ExecutionContextExecutor}
import concurrent.Future
import concurrent.Promise
import concurrent.{ExecutionContext, ExecutionContextExecutor, Future, Promise}
import util.{Try, Success}
import LibUV.Buffer
import LibUVConstants.check

object EventLoop extends ExecutionContextExecutor:
import LibUV.*, LibUVConstants.*
Expand All @@ -18,7 +14,7 @@ object EventLoop extends ExecutionContextExecutor:
private val taskQueue = ListBuffer[Runnable]()
private val handle = stdlib.malloc(uv_handle_size(UV_PREPARE_T))

check(uv_prepare_init(loop, handle), "uv_prepare_init")
checkError(uv_prepare_init(loop, handle), "uv_prepare_init")

val prepareCallback = CFuncPtr1.fromScalaFunction[PrepareHandle, Unit]:
(handle: PrepareHandle) =>
Expand All @@ -33,7 +29,7 @@ object EventLoop extends ExecutionContextExecutor:

def execute(runnable: Runnable): Unit =
taskQueue += runnable
check(uv_prepare_start(handle, prepareCallback), "uv_prepare_start")
checkError(uv_prepare_start(handle, prepareCallback), "uv_prepare_start")

def reportFailure(t: Throwable): Unit =
println(s"Future failed with Throwable $t:")
Expand All @@ -46,177 +42,3 @@ object EventLoop extends ExecutionContextExecutor:
println(s"uv_run returned $continue")

private val bootstrapFuture = Future(run())(ExecutionContext.global)

@link("uv")
@extern
object LibUV:
type PipeHandle = Ptr[Byte]
type PollHandle = Ptr[Ptr[Byte]]
type TCPHandle = Ptr[Byte]

type TTYHandle = Ptr[Byte]
type Loop = Ptr[Byte]
type Buffer = CStruct2[Ptr[Byte], CSize]
type WriteReq = Ptr[Ptr[Byte]]
type ShutdownReq = Ptr[Ptr[Byte]]
type Connection = Ptr[Byte]
type ConnectionCB = CFuncPtr2[TCPHandle, Int, Unit]
type AllocCB = CFuncPtr3[TCPHandle, CSize, Ptr[Buffer], Unit]
type ReadCB = CFuncPtr3[TCPHandle, CSSize, Ptr[Buffer], Unit]
type WriteCB = CFuncPtr2[WriteReq, Int, Unit]
type ShutdownCB = CFuncPtr2[ShutdownReq, Int, Unit]
type CloseCB = CFuncPtr1[TCPHandle, Unit]
type PollCB = CFuncPtr3[PollHandle, Int, Int, Unit]

type PrepareHandle = Ptr[Byte]
type TimerHandle = Ptr[Byte]
type PrepareCB = CFuncPtr1[PrepareHandle, Unit]
type TimerCB = CFuncPtr1[TimerHandle, Unit]

def uv_prepare_init(loop: Loop, handle: PrepareHandle): Int = extern
def uv_prepare_start(handle: PrepareHandle, cb: PrepareCB): Int = extern
def uv_prepare_stop(handle: PrepareHandle): Unit = extern

def uv_default_loop(): Loop = extern
def uv_loop_size(): CSize = extern
def uv_is_active(handle: Ptr[Byte]): Int = extern
def uv_handle_size(h_type: Int): CSize = extern
def uv_req_size(r_type: Int): CSize = extern

def uv_tty_init(loop: Loop, handle: TTYHandle, fd: Int, readable: Int): Int =
extern

def uv_tcp_init(loop: Loop, tcp_handle: TCPHandle): Int = extern
def uv_tcp_bind(tcp_handle: TCPHandle, address: Ptr[Byte], flags: Int): Int =
extern

def uv_ip4_addr(address: CString, port: Int, out_addr: Ptr[Byte]): Int =
extern
def uv_ip4_name(address: Ptr[Byte], s: CString, size: Int): Int = extern

def uv_pipe_init(loop: Loop, handle: PipeHandle, ipc: Int): Int = extern
def uv_pipe_open(handle: PipeHandle, fd: Int): Int = extern
def uv_pipe_bind(handle: PipeHandle, socketName: CString): Int = extern

def uv_poll_init_socket(
loop: Loop,
handle: PollHandle,
socket: Ptr[Byte]
): Int = extern
def uv_poll_start(handle: PollHandle, events: Int, cb: PollCB): Int = extern
def uv_poll_stop(handle: PollHandle): Int = extern

def uv_timer_init(loop: Loop, handle: TimerHandle): Int = extern
def uv_timer_start(
handle: TimerHandle,
cb: TimerCB,
timeout: Long,
repeat: Long
): Int = extern
def uv_timer_stop(handle: TimerHandle): Int = extern

def uv_listen(handle: PipeHandle, backlog: Int, callback: ConnectionCB): Int = extern
def uv_accept(server: PipeHandle, client: PipeHandle): Int = extern
def uv_read_start(client: PipeHandle, allocCB: AllocCB, readCB: ReadCB): Int = extern
def uv_write(
writeReq: WriteReq,
client: PipeHandle,
bufs: Ptr[Buffer],
numBufs: Int,
writeCB: WriteCB
): Int = extern
def uv_read_stop(client: PipeHandle): Int = extern
def uv_shutdown(
shutdownReq: ShutdownReq,
client: PipeHandle,
shutdownCB: ShutdownCB
): Int = extern
def uv_close(handle: PipeHandle, closeCB: CloseCB): Unit = extern
def uv_is_closing(handle: PipeHandle): Int = extern
def uv_run(loop: Loop, runMode: Int): Int = extern

def uv_strerror(err: Int): CString = extern
def uv_err_name(err: Int): CString = extern

def uv_fileno(handle: TTYHandle, fileno: Ptr[Int]): Int = extern
def uv_handle_type_name(handle: TTYHandle): Int = extern
def uv_guess_handle(fd: Int): Int = extern

type FSReq = Ptr[Ptr[Byte]]
type FSCB = CFuncPtr1[FSReq, Unit]

def uv_fs_open(
loop: Loop,
req: FSReq,
path: CString,
flags: Int,
mode: Int,
cb: FSCB
): Int = extern
def uv_fs_read(
loop: Loop,
req: FSReq,
fd: Int,
bufs: Ptr[Buffer],
numBufs: Int,
offset: Long,
fsCB: FSCB
): Int = extern
def uv_fs_write(
loop: Loop,
req: FSReq,
fd: Int,
bufs: Ptr[Buffer],
numBufs: Int,
offset: Long,
fsCB: FSCB
): Int = extern
def uv_fs_close(loop: Loop, req: FSReq, fd: Int, fsCB: FSCB): Int = extern
def uv_req_cleanup(req: FSReq): Unit = extern
def uv_fs_get_result(req: FSReq): Int = extern
def uv_fs_get_ptr(req: FSReq): Ptr[Byte] = extern

object LibUVConstants:
import LibUV._

// uv_run_mode
val UV_RUN_DEFAULT = 0
val UV_RUN_ONCE = 1
val UV_RUN_NOWAIT = 2

// UV_HANDLE_T
val UV_PIPE_T = 7
val UV_POLL_T = 8
val UV_PREPARE_T = 9
val UV_PROCESS_T = 10
val UV_TCP_T = 12
val UV_TIMER_T = 13
val UV_TTY_T = 14
val UV_UDP_T = 15

// UV_REQ_T
val UV_WRITE_REQ_T = 3
val UV_SHUTDOWN_REQ_T = 4
val UV_FS_REQ_T = 6

val UV_READABLE = 1
val UV_WRITABLE = 2
val UV_DISCONNECT = 4
val UV_PRIORITIZED = 8

val O_RDWR = 2
val O_CREAT = sys.props("os.name") match
case "Mac OS X" => 512
case _ => 64

val default_permissions = 420 // octal 0644

def check(v: Int, label: String): Int =
if v == 0 then
println(s"$label returned $v")
v
else
val error = fromCString(uv_err_name(v))
val message = fromCString(uv_strerror(v))
println(s"$label returned $v: $error: $message")
v
32 changes: 16 additions & 16 deletions src/main/scala/ch07/curlSync/main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package curlSync

import scalanative.unsigned.UnsignedRichInt
import scalanative.unsafe.*
import scalanative.libc.stdlib.{malloc, free}
import scalanative.libc.stdlib
import scalanative.libc.stdio.{fwrite, stdout}
import scalanative.libc.string.strncpy
import scalanative.libc.string
import LibCurl.*, LibCurlConstants.*
import scala.collection.mutable.HashMap

object curlBasic:
object CurlBasic:
def addHeaders(curl: Curl, headers: Seq[String]): Ptr[CurlSList] =
var slist: Ptr[CurlSList] = null
for h <- headers do addHeader(slist, h)
Expand All @@ -19,35 +19,35 @@ object curlBasic:
def addHeader(slist: Ptr[CurlSList], header: String): Ptr[CurlSList] =
Zone(slist_append(slist, toCString(header))) // 0.5

var request_serial = 0L
var requestSerial = 0L
val responses = HashMap[Long, ResponseState]()

def getSync(url: String, headers: Seq[String] = Seq.empty): ResponseState =
val req_id_ptr = malloc(sizeof[Long]).asInstanceOf[Ptr[Long]]
!req_id_ptr = 1 + request_serial
request_serial += 1
responses(request_serial) = ResponseState()
val reqIdPtr = stdlib.malloc(sizeof[Long]).asInstanceOf[Ptr[Long]]
!reqIdPtr = 1 + requestSerial
requestSerial += 1
responses(requestSerial) = ResponseState()
val curl = easy_init()

Zone:
val url_str = toCString(url)
println(curl_easy_setopt(curl, URL, url_str))

curl_easy_setopt(curl, WRITECALLBACK, Curl.funcToPtr(writeCB))
curl_easy_setopt(curl, WRITEDATA, req_id_ptr.asInstanceOf[Ptr[Byte]])
curl_easy_setopt(curl, WRITEDATA, reqIdPtr.asInstanceOf[Ptr[Byte]])
curl_easy_setopt(curl, HEADERCALLBACK, Curl.funcToPtr(headerCB))
curl_easy_setopt(curl, HEADERDATA, req_id_ptr.asInstanceOf[Ptr[Byte]])
curl_easy_setopt(curl, HEADERDATA, reqIdPtr.asInstanceOf[Ptr[Byte]])

val res = easy_perform(curl)
easy_cleanup(curl)
responses(request_serial)
responses(requestSerial)

def bufferToString(ptr: Ptr[Byte], size: CSize, nmemb: CSize): String =
val byteSize = size * nmemb
val buffer = malloc(byteSize) // removed the +1 s here
strncpy(buffer, ptr, byteSize) // removed the +1 s here
val buffer = stdlib.malloc(byteSize) // removed the +1 s here
string.strncpy(buffer, ptr, byteSize) // removed the +1 s here
val res = fromCString(buffer)
free(buffer)
stdlib.free(buffer)
res

val writeCB = CFuncPtr4.fromScalaFunction[Ptr[Byte], CSize, CSize, Ptr[Byte], CSize]:
Expand Down Expand Up @@ -87,8 +87,8 @@ object curlBasic:
def main(args: String*): Unit =
println("initializing")
global_init(1)
val resp = getSync(args(0))
println(s"done. got response: $resp")
val response = getSync(args(0))
println(s"done. got response: $response")
println("global cleanup...")
global_cleanup()
println("done")

0 comments on commit 5196ea9

Please sign in to comment.