/*
CrossLang is a dynamically-typed scripting language built on
TessesFramework, named in honor of Jesus's sacrifice.
Copyright (C) 2026 Mike Nolan
SPDX-License-Identifier: GPL-3.0-or-later WITH TessesFramework-Exception-1.0
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "CrossLang.hpp"
namespace Tesses::CrossLang {
int64_t TObjectStream::_GetPosInternal() {
return Tesses::Framework::Streams::Stream::GetLength();
}
TObjectStream::TObjectStream(std::shared_ptr gc, TObject obj) {
this->ls = new GCList(gc);
this->ls->Add(obj);
this->obj = obj;
TDictionary *dict;
if (GetObjectHeap(obj, dict)) {
gc->BarrierBegin();
if (!dict->HasValue("Read")) {
dict->DeclareFunction(
gc, "Read", "Read from stream", {"buff", "off", "len"},
[](GCList &ls, std::vector args) -> TObject {
return (int64_t)0;
});
}
if (!dict->HasValue("Write")) {
dict->DeclareFunction(
gc, "Write", "Write to stream", {"buff", "off", "len"},
[](GCList &ls, std::vector args) -> TObject {
return (int64_t)0;
});
}
if (!dict->HasValue("getCanRead")) {
dict->DeclareFunction(
gc, "getCanRead", "Can read from stream", {},
[](GCList &ls, std::vector args) -> TObject {
return false;
});
}
if (!dict->HasValue("getCanWrite")) {
dict->DeclareFunction(
gc, "getCanWrite", "Can write to stream", {},
[](GCList &ls, std::vector args) -> TObject {
return false;
});
}
if (!dict->HasValue("getCanSeek")) {
dict->DeclareFunction(
gc, "getCanSeek", "Can seek in stream", {},
[](GCList &ls, std::vector args) -> TObject {
return false;
});
}
if (!dict->HasValue("getPosition")) {
dict->DeclareFunction(
gc, "getPosition", "Can get position in stream", {},
[](GCList &ls, std::vector args) -> TObject {
return (int64_t)0;
});
}
if (!dict->HasValue("getLength")) {
dict->DeclareFunction(
gc, "getPosition", "Can get position in stream", {},
[this](GCList &ls, std::vector args) -> TObject {
return _GetPosInternal();
});
}
if (!dict->HasValue("getEndOfStream")) {
dict->DeclareFunction(
gc, "getEndOfStream", "Is at end of stream", {},
[](GCList &ls, std::vector args) -> TObject {
return false;
});
}
gc->BarrierEnd();
}
}
bool TObjectStream::EndOfStream() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
auto res = dict->CallMethod(*ls, "getEndOfStream", {});
bool r;
if (GetObject(res, r))
return r;
}
return false;
}
size_t TObjectStream::Read(uint8_t *buff, size_t sz) {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
GCList ls2(this->ls->GetGC());
TByteArray *arr = TByteArray::Create(ls2);
arr->data.resize(sz);
auto res =
dict->CallMethod(ls2, "Read", {arr, (int64_t)0L, (int64_t)sz});
memcpy(buff, arr->data.data(), std::min(sz, arr->data.size()));
int64_t r;
if (GetObject(res, r))
return r;
}
return 0;
}
size_t TObjectStream::Write(const uint8_t *buff, size_t sz) {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
GCList ls2(this->ls->GetGC());
TByteArray *arr = TByteArray::Create(ls2);
arr->data.resize(sz);
memcpy(arr->data.data(), buff, sz);
auto res =
dict->CallMethod(ls2, "Write", {arr, (int64_t)0L, (int64_t)sz});
int64_t r;
if (GetObject(res, r))
return r;
}
return 0;
}
bool TObjectStream::CanRead() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
auto res = dict->CallMethod(*ls, "getCanRead", {});
bool r;
if (GetObject(res, r))
return r;
}
return false;
}
bool TObjectStream::CanWrite() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
auto res = dict->CallMethod(*ls, "getCanWrite", {});
bool r;
if (GetObject(res, r))
return r;
}
return false;
}
bool TObjectStream::CanSeek() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
auto res = dict->CallMethod(*ls, "getCanSeek", {});
bool r;
if (GetObject(res, r))
return r;
}
return false;
}
int64_t TObjectStream::GetPosition() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
auto res = dict->CallMethod(*ls, "getPosition", {});
int64_t r;
if (GetObject(res, r))
return r;
}
return 0;
}
int64_t TObjectStream::GetLength() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
auto res = dict->CallMethod(*ls, "getEndOfStream", {});
bool r;
if (GetObject(res, r))
return r;
}
return Tesses::Framework::Streams::Stream::GetLength();
}
void TObjectStream::Flush() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
dict->CallMethod(*ls, "Flush", {});
}
}
void TObjectStream::Seek(int64_t pos,
Tesses::Framework::Streams::SeekOrigin whence) {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
dict->CallMethod(
*ls, "Seek",
{pos,
(int64_t)(whence == Tesses::Framework::Streams::SeekOrigin::Begin
? 0
: whence ==
Tesses::Framework::Streams::SeekOrigin::Current
? 1
: 2)});
}
}
void TObjectStream::Close() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
dict->CallMethod(*ls, "Dispose", {});
}
}
TObjectStream::~TObjectStream() {
TDictionary *dict;
if (GetObjectHeap(this->obj, dict)) {
dict->CallMethod(*ls, "Dispose", {});
}
delete this->ls;
}
} // namespace Tesses::CrossLang