/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2019 Telegram Systems LLP */ #pragma once #include "common/refint.h" #include "vm/cells.h" #include "vm/cellslice.h" #include "vm/cellparse.hpp" #include namespace vm { namespace fmt { // main idea: use cs >> i(32,x) >> ... or cs >> i32(x) to deserialize integers, instead of cs.write().fetch_long(32, true) // and cb << i(32,x+y) or cb << i32(x+y) will serialize 32-bit integers // i, u, i16, u16, i32, u32, ub=u1, ib=i1 for integers template class ConstInt { int bits; T value; public: ConstInt(int _bits, T _val) : bits(_bits), value(_val) { } bool serialize(CellBuilder& cb) const { if (C) { return (S ? cb.store_long_rchk_bool(value, bits) : cb.store_ulong_rchk_bool(value, bits)); } else { return cb.store_long_bool(value, bits); } } bool deserialize(CellSlice& cs) const { if (S) { long long x; return cs.fetch_long_bool(bits, x) && x == value; } else { unsigned long long x; return cs.fetch_ulong_bool(bits, x) && x == value; } } }; template class Int { int bits; T& value; public: Int(int _bits, T& _val) : bits(_bits), value(_val) { } bool deserialize(CellSlice& cs) const { if (S) { long long x; if (cs.fetch_long_bool(bits, x)) { value = static_cast(x); return true; } } else { unsigned long long x; if (cs.fetch_ulong_bool(bits, x)) { value = static_cast(x); return true; } } return false; } bool serialize(CellBuilder& cb) const { if (C) { return S ? cb.store_long_rchk_bool(value, bits) : cb.store_ulong_rchk_bool(value, bits); } else { return cb.store_long_bool(value, bits); } } }; template class PrefetchInt { int bits; T& value; public: PrefetchInt(int _bits, T& _val) : bits(_bits), value(_val) { } bool deserialize(CellSlice& cs) const { if (S) { long long x; if (cs.prefetch_long_bool(bits, x)) { value = static_cast(x); return true; } } else { unsigned long long x; if (cs.prefetch_ulong_bool(bits, x)) { value = static_cast(x); return true; } } return false; } }; template class ConstRefInt { int bits; const td::RefInt256& value; public: ConstRefInt(int _bits, const td::RefInt256& _val) : bits(_bits), value(_val) { } bool serialize(CellBuilder& cb) const { return value.not_null() && cb.store_int256_bool(*value, bits, S); } }; template class ConstRefIntVal { int bits; td::RefInt256 value; public: ConstRefIntVal(int _bits, const td::RefInt256& _val) : bits(_bits), value(_val) { } ConstRefIntVal(int _bits, td::RefInt256&& _val) : bits(_bits), value(std::move(_val)) { } bool serialize(CellBuilder& cb) const { return value.not_null() && cb.store_int256_bool(*value, bits, S); } }; template class ConstBigInt { int bits; const td::BigInt256& value; public: ConstBigInt(int _bits, const td::BigInt256& _val) : bits(_bits), value(_val) { } bool serialize(CellBuilder& cb) const { return cb.store_int256_bool(value, bits, S); } }; template class RefInt { int bits; td::RefInt256& value; public: RefInt(int _bits, td::RefInt256& _val) : bits(_bits), value(_val) { } bool deserialize(CellSlice& cs) const { value = cs.fetch_int256(bits, S); return value.not_null(); } bool serialize(CellBuilder& cb) const { return value.not_null() && cb.store_int256_bool(*value, bits, S); } }; inline ConstRefInt i(int l, const td::RefInt256& val) { return {l, val}; } inline ConstRefIntVal i(int l, td::RefInt256&& val) { return {l, std::move(val)}; } inline ConstBigInt i(int l, const td::BigInt256& val) { return {l, val}; } inline RefInt i(int l, td::RefInt256& val) { return {l, val}; } inline ConstRefInt u(int l, const td::RefInt256& val) { return {l, val}; } inline ConstRefIntVal u(int l, td::RefInt256&& val) { return {l, std::move(val)}; } inline ConstBigInt u(int l, const td::BigInt256& val) { return {l, val}; } inline RefInt u(int l, td::RefInt256& val) { return {l, val}; } template const ConstInt i(int l, const T& val) { return {l, val}; } template Int i(int l, T& val) { return {l, val}; } template PrefetchInt pi(int l, T& val) { return {l, val}; } template const ConstInt u(int l, const T& val) { return {l, val}; } template Int u(int l, T& val) { return {l, val}; } template PrefetchInt pu(int l, T& val) { return {l, val}; } template const ConstInt iw(int l, const T& val) { return {l, val}; } template Int iw(int l, T& val) { return {l, val}; } inline ConstInt ib(bool flag) { return {1, flag}; } template Int ib(T& val) { return {1, val}; } template PrefetchInt pib(T& val) { return {1, val}; } inline ConstInt ub(bool flag) { return {1, flag}; } template Int ub(T& val) { return {1, val}; } template PrefetchInt pub(T& val) { return {1, val}; } inline ConstInt i8(signed char val) { return {8, val}; } template Int i8(T& val) { return {8, val}; } inline ConstInt u8(unsigned char val) { return {8, val}; } template Int u8(T& val) { return {8, val}; } inline ConstInt i16(short val) { return {16, val}; } template Int i16(T& val) { static_assert(sizeof(T) >= 2, "i16 needs at least 16-bit integer variable as a result"); return {16, val}; } inline ConstInt u16(unsigned short val) { return {16, val}; } template Int u16(T& val) { static_assert(sizeof(T) >= 2, "u16 needs at least 16-bit integer variable as a result"); return {16, val}; } template const ConstInt i32(const T& val) { return {32, val}; } template Int i32(T& val) { static_assert(sizeof(T) >= 4, "i32 needs at least 32-bit integer variable as a result"); return {32, val}; } template PrefetchInt pi32(T& val) { static_assert(sizeof(T) >= 4, "pi32 needs at least 32-bit integer variable as a result"); return {32, val}; } template const ConstInt u32(const T& val) { return {32, val}; } template Int u32(T& val) { static_assert(sizeof(T) >= 4, "u32 needs at least 32-bit integer variable as a result"); return {32, val}; } template PrefetchInt pu32(T& val) { static_assert(sizeof(T) >= 4, "pu32 needs at least 32-bit integer variable as a result"); return {32, val}; } template const ConstInt i64(const T& val) { return {64, val}; } template Int i64(T& val) { static_assert(sizeof(T) >= 8, "i64 needs 64-bit integer variable as a result"); return {64, val}; } template const ConstInt u64(const T& val) { return {64, val}; } template Int u64(T& val) { static_assert(sizeof(T) >= 8, "u64 needs 64-bit integer variable as a result"); return {64, val}; } /* * * non-integer types * */ // cr(Ref& cell_ref) for (de)serializing cell references class ConstCellRef { const td::Ref& value; public: ConstCellRef(const td::Ref& _val) : value(_val) { } bool serialize(CellBuilder& cb) const { return cb.store_ref_bool(value); } }; class ConstCellRefVal { td::Ref value; public: ConstCellRefVal(const td::Ref& _val) : value(_val) { } ConstCellRefVal(td::Ref&& _val) : value(std::move(_val)) { } bool serialize(CellBuilder& cb) const { return cb.store_ref_bool(std::move(value)); } }; class CellRefFmt { td::Ref& value; public: CellRefFmt(td::Ref& _val) : value(_val) { } bool deserialize(CellSlice& cs) const { value = cs.fetch_ref(); return value.not_null(); } }; inline ConstCellRef cr(const td::Ref& val) { return {val}; } inline ConstCellRefVal cr(td::Ref&& val) { return {std::move(val)}; } inline CellRefFmt cr(td::Ref& val) { return {val}; } // skip(n) will skip n bits class SkipFmt { int bits; public: explicit SkipFmt(int _bits) : bits(_bits) { } bool deserialize(CellSlice& cs) const { return cs.advance(bits); } }; inline SkipFmt skip(int bits) { return SkipFmt{bits}; } // end will throw an exception if any bits or references remain, or if a previous operation failed // ends similar, but checks only bits class ChkEnd { public: explicit ChkEnd() = default; bool deserialize(CellSlice& cs) const { return (cs.empty() && !cs.size_refs()); } }; class ChkEndS { public: explicit ChkEndS() = default; bool deserialize(CellSlice& cs) const { return cs.empty(); } }; template class Chk { Cond cond; public: template explicit constexpr Chk(Args... args) : cond(args...){}; bool deserialize_ext(CellSlice& cs, bool state) const { if (!state || !cond.deserialize(cs)) { cs.error(); } return true; } }; class ChkOk { public: explicit ChkOk() = default; bool deserialize_ext(CellSlice& cs, bool state) const { if (!state) { cs.error(); } return true; } }; constexpr ChkEnd end = ChkEnd{}; constexpr ChkEndS ends = ChkEndS{}; constexpr Chk okend = Chk{}; constexpr Chk okends = Chk{}; constexpr Chk oke = Chk{}; constexpr ChkOk ok = ChkOk{}; inline ::vm::CellParser parser(CellSlice& cs) { return ::vm::CellParser{cs}; } } // namespace fmt } // namespace vm