Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
101 changes: 101 additions & 0 deletions struct composability prototype/AnyThing.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#Used for props, should be replaced by parametrized props
struct AnyThing:
var p:Pointer[Int]
var ref_count: Pointer[Int]
var free_function: Pointer[Int]

fn __init__[T:CollectionElement](inout self,arg:T):
self.p = __type_of(self.p).alloc(1)
var tmp = UnsafePointer[T].alloc(1)
initialize_pointee_move(tmp,arg)
self.p[]=int(tmp)

self.free_function = __type_of(self.free_function).alloc(1)
fn f(to_free :Int)escaping->None:
var tmp_ = UnsafePointer[T](address=to_free)
destroy_pointee(tmp_)
tmp_.free()
var ptr = UnsafePointer[fn(Int)escaping->None].alloc(1)
initialize_pointee_move[fn(Int)escaping->None](ptr,f)
self.free_function[]=int(ptr)

self.ref_count=Pointer[Int].alloc(1)
self.ref_count[]=1

fn deref[T:CollectionElement](inout self)->T:
return UnsafePointer[T](address=self.p[])[]

fn __getitem__[T:CollectionElement](inout self)->T:
return UnsafePointer[T](address=self.p[])[]

fn set[T:CollectionElement](inout self,arg:T):
UnsafePointer[fn(Int)escaping->None](address=self.free_function[])[](self.p[])
destroy_pointee(UnsafePointer[fn(Int)escaping->None](address=self.free_function[]))
UnsafePointer[fn(Int)escaping->None](address=self.free_function[]).free()
fn f(to_free :Int)escaping->None:
var tmp_ = UnsafePointer[T](address=to_free)
destroy_pointee(tmp_)
tmp_.free()
var ptr = UnsafePointer[fn(Int)escaping->None].alloc(1)
initialize_pointee_move[fn(Int)escaping->None](ptr,f)
self.free_function[]=int(ptr)

var tmp = UnsafePointer[T].alloc(1)
initialize_pointee_move(tmp,arg)
self.p[]=int(tmp)

fn __copyinit__(inout self, other:Self):
self.ref_count = other.ref_count
self.p = other.p
self.ref_count[] += 1
self.free_function=other.free_function

fn __moveinit__(inout self, owned other:Self):
self.ref_count = other.ref_count
self.p = other.p
self.free_function=other.free_function

fn __del__(owned self):
if self.ref_count[] == 1:
#print("del")
UnsafePointer[fn(Int)escaping->None](
address=self.free_function[]
)[](self.p[])
destroy_pointee(
UnsafePointer[fn(Int)escaping->None](
address=self.free_function[]
)
)
UnsafePointer[fn(Int)escaping->None](address=self.free_function[]).free()
self.free_function.free()
self.p.free()
self.ref_count.free()
else:
self.ref_count[]-=1
#print(self.ref_count[])

#def MyFunc2(**args:Prop):
# val_a = args["arg_a"].deref[StringLiteral]()
# val_b = args["arg_b"].deref[Tuple[Int,Int]]()
# print(val_a)
# print(val_b.get[0](),val_b.get[1]())
#
#def main():
# MyFunc2(arg_a = "Hello world",arg_b = (1,2))
#
# tmp = Prop(1.1)
# print(tmp.deref[Float64]())
# cp = tmp
# cp.set("Hello world")
# print(tmp.deref[StringLiteral]())
# for i in range(10):
# tmp2 = Prop(String("hello world")+str(i))
# print(tmp2.deref[String]())
# #tmp2.set(1/i)
# #print(tmp2.deref[Float64]())





#
21 changes: 21 additions & 0 deletions struct composability prototype/Component.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from DomTree import *
from AnyThing import *
from DomEvent import *
alias PropsType = Dict[String,AnyThing]

trait Component(CollectionElement):
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's split this out as the start PR for this. In general I'm favorable towards this, though I don't think we need the component_name, and render should be fn, not def.

@staticmethod
fn component_name()->String:...
fn __init__(inout self): ...
fn event(inout self, e:DomEvent): ...
def render(
inout self,
owned props:PropsType
) ->Element: ...

@value
struct Component_T:
var instance_name:String
var component_name: String
var props: PropsType

214 changes: 214 additions & 0 deletions struct composability prototype/ComponentManager.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
from Component import *
from DomTree import *
from python import Python
@value
struct Instances:
var states: Dict[
String, #InstanceName
UnsafePointer[NoneType]
]

fn __getitem__[
T:Component,
n:StringLiteral
](self)->UnsafePointer[T]:
try:
return self.states[n].bitcast[T]()
except e: ...
return UnsafePointer[T]()


@value
struct ComponentManager[*Ts:Component]:
var states: Dict[
String, #InstanceName
UnsafePointer[NoneType]
]
var types: Dict[String,String] #InstanceName,ComponentName
var previously_rendered_instances: List[String] #InstanceNames

fn __init__(inout self):
constrained[
TsUniques[Ts](),
"Two components have the same name"
]()

self.states = __type_of(self.states)()
self.types = __type_of(self.types)()
self.previously_rendered_instances =
__type_of(self.previously_rendered_instances)()


fn RenderIntoJson[First:Bool=False](
inout self,
inout elements: Element,
)->PythonObject:
try:
var tmp_result = Python.evaluate("lambda **kwargs: kwargs")(
tag=elements.tag,
inner=[]
)
if elements.tag == "TextNode":
tmp_result["value"]=elements.attributes["value"]
else:
for a in elements.attributes:
tmp_result[a[]]=elements.attributes[a[]]
for i in elements.inner:
if i[].isa[Element]():
tmp_result["inner"].append(
self.RenderIntoJson(
i[]._get_ptr[Element]()[]
)
)
@parameter
if First: return Python.import_module("json").dumps(tmp_result)
else: return tmp_result
except e: print("RenderToJson",e)
return None

fn RenderComponentsIntoElements[first:Bool](
inout self,
inout arg: Element
):
#TODO: check not instance_name rendered twice
@parameter
if first: self.previously_rendered_instances.clear()

if arg.component:
var tmp = arg.component._value_copy()
@parameter
fn loop[I:Int]():
if is_component[Ts[I]](tmp.component_name):
self.TsRenderInto[Ts[I]](arg,tmp)
unroll[loop,len(VariadicList(Ts))]()
_=tmp

for i in arg.inner:
if i[].isa[Element]():
if i[]._get_ptr[Element]()[].component:
var tmp = i[]._get_ptr[Element]()[]
self.RenderComponentsIntoElements[False](tmp)
i[]._get_ptr[Element]()[] = tmp

fn CreateInstance[T:Component](
inout self,
c:Component_T
)->UnsafePointer[T]:
var tmp=UnsafePointer[T].alloc(1)
initialize_pointee_move(tmp,T())
self.states[c.instance_name]=tmp.bitcast[NoneType]()
self.types[c.instance_name]=c.component_name
return tmp

fn GetInstance[T:Component](
inout self,
c:Component_T
)->UnsafePointer[T]:
for k in self.states:
if k[] == c.instance_name:
try:
var tmp2= self.states[k[]].bitcast[T]()
return tmp2
except e: print(e)
var tmp = self.CreateInstance[T](c)
return tmp

fn TsRenderInto[T:Component](
inout self,
inout e:Element,
c: Component_T
):
var instance = self.GetInstance[T](c)#T()
try:
var tmp=instance[].render(c.props)
tmp.attributes["data-instance_name"]=c.instance_name
e=tmp
except e:print("TsRenderInto",e)

self.previously_rendered_instances.append(
c.instance_name
)

fn delete_instances[only_unrendered:Bool=False](inout self):
var deleted = Dict[String,Bool]()
for instance_name in self.states:
if self.types.find(instance_name[]):
try:
var tmp_ptr = self.states[instance_name[]]
var t= self.types[instance_name[]]
@parameter
fn loop[I:Int]():
if instance_name[] in deleted: return
if is_component[Ts[I]](t):
try:
@parameter
if only_unrendered:
var found = False
for p in self.previously_rendered_instances:
if p[]==instance_name[]:
found = True
if found: return
_=self.types.pop(instance_name[])
deleted[instance_name[]]=True
destroy_pointee(tmp_ptr.bitcast[Ts[I]]())
tmp_ptr.free()
except e:print("delete_instances/loop",e)
unroll[loop,len(VariadicList(Ts))]()
_=tmp_ptr
except e: print("delete_instances",e)
try:
print("__del__() :",len(deleted))
for i in deleted:
var tmp_del = self.states.pop(i[])
print("\t",i[])
except e: print("delete_instances",e)
@parameter
if only_unrendered == False:
self.previously_rendered_instances=
__type_of(self.previously_rendered_instances)()
_=deleted
_=self.states
_=self.types

fn is_component[T:Component](name:String)->Bool:
return T.component_name()==name

fn TsEquals[T:Component,T2:Component]()->Bool:
return T.component_name() == T2.component_name()

fn TsIndex[*Ts:Component](name:String)->Int:
var result=-1
@parameter
fn loop[I:Int]():
if is_component[Ts[I]](name): result = I
unroll[loop,len(VariadicList(Ts))]()
return result

fn TsCount[T:Component,*Ts:Component]()->Int:
var result=0
@parameter
fn loop[I:Int]():
if TsEquals[Ts[I],T](): result += 1
unroll[loop,len(VariadicList(Ts))]()
return result

fn TsUniques[*Ts:Component]()->Bool:
var result = True
@parameter
fn loop[I:Int]():
if TsCount[Ts[I],Ts]()>1:
result = False
unroll[loop,len(VariadicList(Ts))]()
return result

fn TsContains[*Ts:Component,name:StringLiteral]()->Bool:
var result = False
@parameter
fn loop[I:Int]():
result = result|TsEq[Ts[I],name]()
unroll[loop,len(VariadicList(Ts))]()
return result

fn TsEq[Ts:Component,arg:StringLiteral]()->Bool:
return Ts.component_name() == arg

22 changes: 22 additions & 0 deletions struct composability prototype/DomEvent.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from utils.variant import Variant
from Component import *
from ComponentManager import *

@value
struct DomEvent:
alias MouseEnter = "MouseEnter"
alias Click = "Click"
var target:String #TODO: id attribute
var type: String #TODO: "MouseEnter"
var name:String # On[DomEvent.Click]("name")
var data:String #TODO: json, depend on event type
var Instances: Instances

@value
struct EventHandler:
var type: StringLiteral
var instance_name:String
var event_name:String

fn On[e:StringLiteral](name:StringLiteral)->EventHandler:
return EventHandler(e,"",name)
Loading