diff --git a/interop/src/cangjie/DeserializerBase.cj b/interop/src/cangjie/DeserializerBase.cj new file mode 100644 index 0000000000000000000000000000000000000000..1eed6b67deaad2e1e224256ed875da03d9733270 --- /dev/null +++ b/interop/src/cangjie/DeserializerBase.cj @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package Interop + +import std.binary.* +import std.collection.* + +public class CallbackResource { + public var resourceId: Int32 + public var hold: pointer + public var release: pointer + init(resourceId: Int32, hold: pointer, release: pointer) { + this.resourceId = resourceId + this.hold = hold + this.release = release + } +} + +public open class DeserializerBase { + private var position = 0 + private var length = 96 + private var buffer: Array + + init(buffer: Array, length: Int64) { + this.buffer = buffer + this.length = length + } + + func asArray(position: Int64, length: Int64): ArrayList { + return ArrayList() + } + + func currentPosition(): Int64 { + return this.position + } + + func resetCurrentPosition(): Unit { + this.position = 0 + } + + private func checkCapacity(value: Int64) { + if (value > this.length) { + throw Exception("${value} is less than remaining buffer length") + } + } + + func readInt8(): Int8 { + this.checkCapacity(1) + let res = Int8.readLittleEndian(this.buffer[this.position..this.position+1]) + this.position += 1 + return res + } + + func readInt32(): Int32 { + this.checkCapacity(4) + let res = Int32.readLittleEndian(this.buffer[this.position..this.position+4]) + this.position += 4 + return res + } + + func readInt64(): Int64 { + this.checkCapacity(8) + let res = Int64.readLittleEndian(this.buffer[this.position..this.position+8]) + this.position += 8 + return res + } + + func readPointer(): KPointer { + this.checkCapacity(8) + let res = UInt64.readLittleEndian(this.buffer[this.position..this.position+8]) + this.position += 8 + return res + } + + func readFloat32(): Float32 { + this.checkCapacity(4) + let res = Float32.readLittleEndian(this.buffer[this.position..this.position+4]) + this.position += 4 + return res + } + + func readBoolean(): Bool { + let res = Bool.readLittleEndian(this.buffer[this.position..this.position+1]) + this.position += 1 + return res + } + + // readMaterialized(): object { + // const ptr = this.readPointer() + // return { ptr: ptr } + // } + + func readString(): String { + // TODO + return "value" + } + + func readCustomObject(kind: String): Object{ + throw Exception("readCustomObject") + } + + func readNumber(): Float64 { + let tag = this.readInt8() + if (tag == Tag.UNDEFINED.value) { + throw Exception("Read number can't return undefined.") + } else if (tag == Tag.INT32.value) { + return Float64(this.readInt32()) + } else if (tag == Tag.FLOAT32.value) { + return Float64(this.readFloat32()) + } else { + throw Exception("Unknown number tag: ${tag}") + } + } + + func readCallbackResource(): CallbackResource { + return CallbackResource(this.readInt32(), this.readPointer(), this.readPointer()) + } +} diff --git a/interop/src/cangjie/Finalizable.cj b/interop/src/cangjie/Finalizable.cj new file mode 100644 index 0000000000000000000000000000000000000000..73f7c9f9f2211d0aca2c054b4315f335e26bc2b6 --- /dev/null +++ b/interop/src/cangjie/Finalizable.cj @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package Interop + +public open class Finalizable { + public var ptr: KPointer + public var finalizer: KPointer + + public Finalizable(ptr: KPointer, finalizer: KPointer) { + this.ptr = ptr + this.finalizer = finalizer + } +} \ No newline at end of file diff --git a/interop/src/cangjie/InteropTypes.cj b/interop/src/cangjie/InteropTypes.cj new file mode 100644 index 0000000000000000000000000000000000000000..7d1978584d087057521c3e31150f8d95e1e6c398 --- /dev/null +++ b/interop/src/cangjie/InteropTypes.cj @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package Interop + +import std.collection.* + +type KPointer = UInt64 +type pointer = KPointer +type KInt = Int32 +type KStringPtr = String +type ArrayBuffer = ArrayList +type Callback_RangeUpdate = (index: Int32, mark: pointer, end: Int32) -> Unit +type Callback_String_Void = (str: String) -> Unit +type Callback_Extender_OnProgress = (value: Float32) -> Unit +type Callback_Extender_OnFinish = () -> pointer +type Callback_Extender_OnAnimation = () -> UInt8 \ No newline at end of file diff --git a/interop/src/cangjie/ResourceManager.cj b/interop/src/cangjie/ResourceManager.cj new file mode 100644 index 0000000000000000000000000000000000000000..12e0af7517b6eb05c31c1f99f3fcf465d144a40f --- /dev/null +++ b/interop/src/cangjie/ResourceManager.cj @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package Interop + +import std.binary.* +import std.math.* +import std.collection.* + +type ResourceId = Int32 + +class ResourceInfo { + public var resource: Any + public var holdersCount: Int32 + init(resource: Any, holdersCount: Int32 ) { + this.resource = resource + this.holdersCount = holdersCount + } +} + +public class ResourceHolder { + private static var nextResourceId: ResourceId = 100 + private var resources: HashMap = HashMap() + private static var _instance: ?ResourceHolder = Option.None + static func instance(): ResourceHolder { + ResourceHolder._instance = match (ResourceHolder._instance) { + case Some(resourceHolder) => resourceHolder + case _ => ResourceHolder() + } + if (let Some(rh) <- ResourceHolder._instance) { + return rh + } else { + throw Exception() + } + } + public func hold(resourceId: ResourceId) { + match(this.resources.get(resourceId)) { + case Some(resource) => resource.holdersCount++ + case _ => throw Exception("Resource ${resourceId} does not exists, can not hold") + } + } + + public func release(resourceId: ResourceId) { + let resource = match (this.resources.get(resourceId)) { + case Some(resource) => resource + case _ => throw Exception("Resource ${resourceId} does not exists, can not hold") + } + resource.holdersCount-- + if (resource.holdersCount <= 0) { + this.resources.remove(resourceId) + } + } + + public func registerAndHold(resource: Any): ResourceId { + ResourceHolder.nextResourceId += 1 + let resourceId = ResourceHolder.nextResourceId + this.resources.put(resourceId, ResourceInfo(resource, resourceId)) + return resourceId + } + + public func get(resourceId: ResourceId): Any { + match(this.resources.get(resourceId)) { + case Some(resource) => return resource.resource + case _ => throw Exception("Resource ${resourceId} does not exists") + } + } +} diff --git a/interop/src/cangjie/SerializerBase.cj b/interop/src/cangjie/SerializerBase.cj new file mode 100644 index 0000000000000000000000000000000000000000..683dcfcc8d4dc314b8f66c22ee62649968812623 --- /dev/null +++ b/interop/src/cangjie/SerializerBase.cj @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package Interop + +import std.binary.* +import std.math.* +import std.reflect.* +import std.collection.* + +public enum RuntimeType { + |UNEXPECTED + |NUMBER + |STRING + |OBJECT + |BOOLEAN + |UNDEFINED + |BIGINT + |FUNCTION + |SYMBOL + |MATERIALIZED + prop ordinal: Int32 { + get() { + match (this) { + case UNEXPECTED => -1 + case NUMBER => 1 + case STRING => 2 + case OBJECT => 3 + case BOOLEAN => 4 + case UNDEFINED => 5 + case BIGINT => 6 + case FUNCTION => 7 + case SYMBOL => 8 + case MATERIALIZED => 9 + } + } + } +} + + +/* Serialization extension point */ +public abstract class CustomSerializer { + public var supported: Array + init(supported: Array) { + this.supported = supported + } + public func supports(kind: String): Bool { return this.supported.contains(kind) } + public func serialize(serializer: SerializerBase, value: Object, kind: String): Unit {} + var next: ?CustomSerializer = Option.None +} + +public open class SerializerBase { + protected var isHolding: Bool = false + private var position: Int64 = 0 + private var buffer: ArrayList = ArrayList() + + private static var customSerializers: ?CustomSerializer = Option.None + static func registerCustomSerializer(serializer: CustomSerializer) { + //TODO + } + + init() { + this.buffer = ArrayList(Array(96, repeat: UInt8(0))) + } + public open func release() { + this.isHolding = false + // todo handle release resources + this.position = 0 + } + func asArray(): ArrayList { + return this.buffer + } + func length(): Int32 { + return Int32(this.position) + } + func currentPosition(): Int64 { return this.position } + private func checkCapacity(value: Int64) { + if (value < 1) { + throw Exception("${value} is less than 1") + } + var buffSize = this.buffer.size + if (this.position > buffSize - value) { + let minSize = this.position + value + let resizedSize = max(minSize, Int64(round(3.0 * Float64(buffSize) / 2.0))) + var resizedBuffer = ArrayList(resizedSize) + for (i in 0..this.buffer.size) { + resizedBuffer.append(this.buffer[i]) + } + this.buffer = resizedBuffer + } + } + func writeCustomObject(kind: String, value: Any): Unit { + var current = SerializerBase.customSerializers + // TODO + println("Unsupported custom serialization for ${kind}, write undefined") + this.writeInt8(Tag.UNDEFINED.value) + } + private var heldResources: ArrayList = ArrayList() + func holdAndWriteCallback(callback: Any): ResourceId { + let resourceId = ResourceHolder.instance().registerAndHold(callback) + this.heldResources.append(resourceId) + this.writeInt32(resourceId) + this.writePointer(0) + this.writePointer(0) + this.writePointer(0) + this.writePointer(0) + return resourceId + } + func holdAndWriteCallback(callback: Any, hold: KPointer, release: KPointer, call: KPointer, callSync: KPointer): ResourceId { + let resourceId = ResourceHolder.instance().registerAndHold(callback) + this.heldResources.append(resourceId) + this.writeInt32(resourceId) + this.writePointer(hold) + this.writePointer(release) + this.writePointer(call) + this.writePointer(callSync) + return resourceId + } + func writeFunction(value: Any): Unit { + // TODO + } + private func setBytes(position: Int64, value: T): Unit where T <: LittleEndianOrder{ + var arr = Array(100, repeat: 0) + let n = value.writeLittleEndian(arr) + this.checkCapacity(n) + for (i in 0..n) { + this.buffer[this.position + i] = arr[i] + } + this.position += n + } + func writeTag(tag: Int32): Unit { + this.setBytes(this.position, tag) + } + func writeNumber(value: ?Float32): Unit { + if (let Some(value) <- value) { + if(value == Float32(Int32(value))) { + this.writeNumber(Int32(value)) + } else { + this.setBytes(this.position, Tag.FLOAT32.value) + this.setBytes(this.position, value) + } + } + else { + this.buffer[Int64(this.position)] = UInt8(RuntimeType.UNDEFINED.ordinal) + this.position++ + } + } + func writeNumber(value: ?Float64): Unit { + if (let Some(value) <- value) { + if(value == Float64(Int32(value))) { + this.writeNumber(Int32(value)) + } else { + this.setBytes(this.position, Tag.FLOAT32.value) + this.setBytes(this.position, Float32(value)) + } + } + else { + this.buffer[Int64(this.position)] = UInt8(RuntimeType.UNDEFINED.ordinal) + this.position++ + } + } + func writeNumber(value: ?Int32): Unit { + if (let Some(value) <- value) { + this.setBytes(this.position, Tag.INT32.value) + this.setBytes(this.position, value) + } + else { + this.buffer[Int64(this.position)] = UInt8(RuntimeType.UNDEFINED.ordinal) + this.position++ + } + } + func writeNumber(value: ?Int64): Unit { + if (let Some(value) <- value) { + this.setBytes(this.position, Tag.INT32.value) + this.setBytes(this.position, Int32(value)) + } + else { + this.buffer[Int64(this.position)] = UInt8(RuntimeType.UNDEFINED.ordinal) + this.position++ + } + } + func writeInt8(value: Int8): Unit { + this.setBytes(this.position, value) + } + func writeInt8(value: Int32): Unit { + this.setBytes(this.position, Int8(value)) + } + func writeInt32(value: Int32): Unit { + this.setBytes(this.position, Int32(value)) + } + func writeInt64(value: Int64): Unit { + this.setBytes(this.position, Int64(value)) + } + func writeFloat32(value: Float32): Unit { + this.setBytes(this.position, value) + } + func writePointer(ptr: UInt64): Unit { + this.setBytes(this.position, ptr) + } + func writeBoolean(value: ?Bool): Unit { + this.checkCapacity(1) + if(let Some(value) <- value) { + this.setBytes(this.position, value) + } + else { + this.buffer[Int64(this.position)] = UInt8(RuntimeType.UNDEFINED.ordinal) + this.position++ + } + } + func writeMaterialized(value: Object): Unit { + // TODO + } + func writeString(value: String): Unit { + this.checkCapacity(4 + value.size * 4 + 1) // length, data + this.writeInt32(Int32(value.size + 1)) + for (i in 0..value.size) { + this.setBytes(this.position, value[i]) + } + this.writeInt8(Int8(0)) + } + func writeBuffer(value: ArrayList) { + // TODO + // this.writePointer(42) + // this.writeInt64(value.size) + } +} + +public open class DateCustomSerializer <: CustomSerializer { + public DateCustomSerializer() { + super(["Date"]) + } + public func serialize(serializer: SerializerBase, value: Ark_CustomObject, kind: String): Unit { + serializer.writeString("{}") + } +} + +public open class Ark_CustomObject <: Ark_ObjectBase { + init() { + SerializerBase.registerCustomSerializer(DateCustomSerializer()) + } +} diff --git a/interop/src/cangjie/Tag.cj b/interop/src/cangjie/Tag.cj new file mode 100644 index 0000000000000000000000000000000000000000..8c5cc317f9721d5cad36b5cae262e759eb1eac4c --- /dev/null +++ b/interop/src/cangjie/Tag.cj @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package Interop + +public open class Tag { + public static var UNDEFINED: Tag = Tag(101) + public static var INT32: Tag = Tag(102) + public static var FLOAT32: Tag = Tag(103) + public static var STRING: Tag = Tag(104) + public static var LENGTH: Tag = Tag(105) + public static var RESOURCE: Tag = Tag(106) + public static var OBJECT: Tag = Tag(107) + public var value: Int8 + Tag (arg0: Int8) { + value = arg0 + } +} diff --git a/interop/src/cangjie/cjpm.toml b/interop/src/cangjie/cjpm.toml new file mode 100644 index 0000000000000000000000000000000000000000..d292298862672bb07ad633fba6687dc2cc3d7785 --- /dev/null +++ b/interop/src/cangjie/cjpm.toml @@ -0,0 +1,12 @@ +[dependencies] +[package] + cjc-version = "0.56.4" + compile-option = "" + description = "config file for cj build" + link-option = "" + name = "Interop" + output-type = "static" + src-dir = "." + target-dir = "./build/cj" + version = "1.0.0" + package-configuration = {}