Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cyjs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ._cyjs import (
CancelledError,
Context,
JSClass,
JSError,
JSFunction,
Object,
Expand All @@ -15,6 +16,7 @@
__all__ = (
"CancelledError",
"Context",
"JSClass",
"JSError",
"JSFunction",
"Object",
Expand Down
82 changes: 78 additions & 4 deletions cyjs/_cyjs.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ cdef extern from "bridge.h":
bint promise
)

# Shortcuts for Making global variables, these are not
# in quickjs's header file but are useful to have here
int CYJS_NewGlobalCConstructor2(JSContext *ctx,
JSValue func_obj,
const char *name,
JSValue proto)

JSValue CYJS_NewGlobalCConstructor(JSContext *ctx, const char *name, JSCFunctionMagic func, int length, JSValue proto, int magic)
ctypedef JSValue (*cyjs_get)(JSContext *ctx, JSValue this_val, int magic) noexcept with gil
ctypedef JSValue (*cyjs_set)(JSContext *ctx, JSValue this_val, JSValue value, int magic ) noexcept with gil
JSCFunctionListEntry* CYJS_MakeJSCFunctionListEntries(
list names,
cyjs_get get,
cyjs_set set
) except NULL

cdef class JSError(Exception):
@staticmethod
cdef JSError new(JSContext* ctx, JSValue value)
Expand Down Expand Up @@ -102,7 +118,7 @@ cdef class PromiseHook:





cdef class Runtime:
"""
Expand Down Expand Up @@ -141,8 +157,13 @@ cdef class Runtime:
cpdef void update_statck_top(self)

cpdef object set_promise_hook(self, object func)


cpdef JSClass new_class(
self,
object py_type,
object name =*,
object attrs=*
)


cdef class Object:
cdef:
Expand Down Expand Up @@ -192,11 +213,53 @@ cdef class JSFunction:
cdef JSValue call_js(self, JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic) noexcept


# Inspired by pyduktape
cdef class JSRef:
"""Used for acting as a bridge between Javascript and Python attributes"""
cdef:
readonly Context context
JSContext* ctx
JSValue value
object ref
list slots # list of exposable attributes to chain to JS_CGETSET_MAGIC_DEF


@staticmethod
cdef JSRef new(Context context, JSValue value, object ref, list slots)

# cdef int has(self, JSAtom at) except -1
# cdef JSValue get(self, JSAtom at)


cdef class JSClass:
"""Enables Class Creation (Mostly internal)"""
cdef:
readonly Runtime runtime
readonly JSClassID id # expose to python for debugging
object py_type
JSClassDef cls_def
list properties
JSCFunctionListEntry* entries

@staticmethod
cdef JSClass new(
Runtime runtime,
object py_type,
object class_name=*,
list properties=*
)






# This helps with benchmarking and eliminating a few options when
# crunching some more obvious cases...

ctypedef fused quickjs_type_t:
JSFunction
JSRef
Object
Exception
dict
Expand All @@ -215,7 +278,11 @@ cdef class Context:
JSContext* ctx
# incase a hook of some kind with a void happens to throw an exception we can capture it.
object _cb_exception

# This will allow us to attempt to safely hook JSClassIDs to Python classes.
dict _pyjs_classes
# helps with figuring out if a type can be safely JSRef'd
set _registered_py_types


# NOTE: I'm Putting type ignores here because
# C function "get_exception" is implemented in pxd definition of C class "Context" without the "inline" qualifier
Expand Down Expand Up @@ -296,3 +363,10 @@ cdef class Context:
bint promise =*
)

# Wraps functions and registers JSClass
# to start performing conversions with it.
cpdef object add_class(
self,
JSClass js_cls
)

42 changes: 41 additions & 1 deletion cyjs/_cyjs.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from collections.abc import Callable
from collections.abc import Callable, Iterable
from enum import IntEnum
from typing import Any, Generic, ParamSpec, TypeVar

Expand Down Expand Up @@ -68,6 +68,24 @@ class Runtime:
self,
func: Callable[["Context", PromiseHookType, Promise, Promise | None], None],
) -> object: ...
def new_class(
self,
py_type: type[_T],
name: str | bytes | bytearray | memoryview = ...,
attrs: Iterable[str] = ...,
) -> JSClass[_T]:
"""Registers a python class to bind with quickjs

:param py_type: the python type to bind with.
:param name: an alternative name to provide \
to the given type object. The Default name \
will get derrived from py_type if name is None.
:param attrs: an iterable of readable public properties \
that this class should allow quickjs to be able to have \
access to and read. \
NOTE: functions and methods haven't been implemented yet \
but might be planned in a future update.
"""

class _OView:
def __init__(self, obj: Object) -> None: ...
Expand Down Expand Up @@ -137,6 +155,8 @@ class Object:
"""evaluates javascript module code"""
...

# TODO: Provide Generic typehinting capabilites in the actual cython code.
# Like how frozenlist does it or through a simillar mechanism...
class JSFunction(Generic[_P, _T]):
context: Context

Expand All @@ -145,7 +165,19 @@ class JSFunction(Generic[_P, _T]):
def object(self) -> Object:
pass

class JSClass(Generic[_T]):
runtime: Runtime
id: int

@property
def type(self) -> type[_T]:
"""returns the original type provided to be binded to quickjs"""
@property
def name(self) -> str:
"""provides the name of the given JSClass through it's JSClassDef structure"""

class Context:
runtime: Runtime
def __init__(
self,
runtime: Runtime = ...,
Expand Down Expand Up @@ -232,6 +264,14 @@ class Context:
backtrace_barrier: bool = ...,
promise: bool = ...,
) -> Any: ...
def add_class(self, js_cls: JSClass[Any]):
"""
binds a JSClass Globally to globalThis
:param js_cls: the Javascript Class to bind \
these can be created via obtaining the runtime \
attribute of this context \
as a shortcut and calling `runtime.new_class(...)` beforehand
"""

class CancelledError(Exception):
"""Promise was rejected"""
Expand Down
Loading
Loading