Flutter插件bcs的使用方法

Flutter插件bcs的使用方法

本库实现了在Dart中的二进制规范序列化(BCS)。

import 'package:bcs/bcs.dart';

// 定义UID为一个32字节的数组,并添加从十六进制字符串到字节数组的转换
final UID = Bcs.fixedArray(32, Bcs.u8()).transform(
  input: (id) => fromHEX(id.toString()),
  output: (id) => toHEX(Uint8List.fromList(id)),
);

final Coin = Bcs.struct('Coin', {
  "id": UID,
  "value": Bcs.u64(),
});

// 反序列化:BCS字节流转换为Coin对象
final bcsBytes = Coin.serialize({
  "id": '0000000000000000000000000000000000000000000000000000000000000001',
  "value": BigInt.from(1000000),
}).toBytes();

final coin = Coin.parse(bcsBytes);

// 序列化:对象转换为字节流 - 一个类型为Coin的Option
final hex = Bcs.option(Coin).serialize(coin).toHex();

print(hex);

Flutter插件bcs的描述

BCS定义了数据如何被序列化,且序列化的结果不包含任何类型信息。为了能够将数据进行序列化并稍后反序列化,必须创建一个模式(基于内置的原语,如stringu64)。序列化后的字节流中没有任何类型提示,因此用于解码的模式必须与用于编码数据的模式相匹配。

bcs库可以用来定义可以对BCS编码的数据进行序列化和反序列化的模式。

基础类型

BCS支持许多内置的基本类型,这些基本类型可以组合成更复杂的类型。下表列出了可用的基本类型:

方法 Dart 类型 Dart 输入类型 描述
bool bool bool 布尔类型(转换为true/false
u8, u16, u32 int int 无符号整数类型
u64, u128, u256 BigInt BigInt 无符号整数类型,解码为string以允许JSON序列化
uleb128 int int 无符号LEB128整数类型
string String String UTF-8 编码字符串
bytes(size) Uint8List Uint8List 固定长度字节
import 'package:bcs/bcs.dart';

final u8 = Bcs.u8().serialize(100).toBytes();
final u64 = Bcs.u64().serialize(BigInt.from(1000000)).toBytes();
final u128 = Bcs.u128().serialize('100000010000001000000').toBytes();

final str = Bcs.string().serialize('this is an ascii string').toBytes();
final bytes = Bcs.bytes(4).serialize(Uint8List.fromList([1, 2, 3, 4])).toBytes();

final parsedU8 = Bcs.u8().parse(u8);
final parsedU64 = Bcs.u64().parse(u64);
final parsedU128 = Bcs.u128().parse(u128);

final parsedStr = Bcs.string().parse(str);
final parsedBytes = Bcs.bytes(4).parse(bytes);

复合类型

对于大多数用例,您会希望将基础类型组合成更复杂的类型,如vectorsstructsenums。下表列出了可用于创建复合类型的可用方法:

方法 描述
vector(T type) T类型的可变长度列表
fixedArray(size, T) T类型的固定长度数组
option(T type) 类型为Tnull的值
enumeration(name, values) 表示所提供值之一的枚举值
struct(name, fields) 具有指定类型字段的结构体
tuple(types) 指定类型的元组
map(K, V) 类型为K的键到类型为V的值的映射
import 'package:bcs/bcs.dart';

// 向量
final intList = Bcs.vector(Bcs.u8()).serialize([1, 2, 3, 4, 5]).toBytes();
final stringList = Bcs.vector(Bcs.string()).serialize(['a', 'b', 'c']).toBytes();

// 数组
final intArray = Bcs.fixedArray(4, Bcs.u8()).serialize([1, 2, 3, 4]).toBytes();
final stringArray = Bcs.fixedArray(3, Bcs.string()).serialize(['a', 'b', 'c']).toBytes();

// 选项
final option = Bcs.option(Bcs.string()).serialize('some value').toBytes();
final nullOption = Bcs.option(Bcs.string()).serialize(null).toBytes();

// 枚举
final MyEnum = Bcs.enumeration('MyEnum', {
	"NoType": null,
	"Int": Bcs.u8(),
	"String": Bcs.string(),
	"Array": Bcs.fixedArray(3, Bcs.u8()),
});

final noTypeEnum = MyEnum.serialize({ "NoType": null }).toBytes();
final intEnum = MyEnum.serialize({ "Int": 100 }).toBytes();
final stringEnum = MyEnum.serialize({ "String": 'string' }).toBytes();
final arrayEnum = MyEnum.serialize({ "Array": [1, 2, 3] }).toBytes();

// 结构体
final MyStruct = Bcs.struct('MyStruct', {
	"id": Bcs.u8(),
	"name": Bcs.string(),
});

final struct = MyStruct.serialize({ "id": 1, "name": 'name' }).toBytes();

// 元组
final tuple = Bcs.tuple([Bcs.u8(), Bcs.string()]).serialize([1, 'name']).toBytes();

// 映射
final map = Bcs
	.map(Bcs.u8(), Bcs.string())
	.serialize(
		{
			1: 'one',
			2: 'two',
    }).toBytes();

// 将数据解析回原始类型

// 向量
final parsedIntList = Bcs.vector(Bcs.u8()).parse(intList);
final parsedStringList = Bcs.vector(Bcs.string()).parse(stringList);

// 数组
final parsedIntArray = Bcs.fixedArray(4, Bcs.u8()).parse(intArray);

// 选项
final parsedOption = Bcs.option(Bcs.string()).parse(option);
final parsedNullOption = Bcs.option(Bcs.string()).parse(nullOption);

// 枚举
final parsedNoTypeEnum = MyEnum.parse(noTypeEnum);
final parsedIntEnum = MyEnum.parse(intEnum);
final parsedStringEnum = MyEnum.parse(stringEnum);
final parsedArrayEnum = MyEnum.parse(arrayEnum);

// 结构体
final parsedStruct = MyStruct.parse(struct);

// 元组
final parsedTuple = Bcs.tuple([Bcs.u8(), Bcs.string()]).parse(tuple);

// 映射
final parsedMap = Bcs.map(Bcs.u8(), Bcs.string()).parse(map);

泛型

要定义一个泛型结构体或枚举,您可以定义一个泛型类型脚本辅助函数。

import 'package:bcs/bcs.dart';
import 'package:bcs/bcs_type.dart';

// T 类型脚本泛型是通用值的类型占位符
// T 参数将是创建具体容器类型实例时传递的BCS类型
BcsType Container<T>(BcsType<T, T> T) {
	return Bcs.struct('Container<T>', {
		"contents": T,
	});
}

// 在序列化时,我们必须传递用于`T`的类型
final bytes = Container(Bcs.u8()).serialize({ "contents": 100 }).toBytes();

// 或者我们可以将具体的类型保存为变量
// final U8Container = Container(Bcs.u8());
// final bytes = U8Container.serialize({ "contents": 100 }).toBytes();

// 使用多个泛型
BcsType VecMap<K, V>(BcsType<K, K> K, BcsType<V, V> V) {
	// 您可以使用泛型参数名称来命名您的类型
	return Bcs.struct(
		"VecMap<${K.name}, ${V.name}>",
		{
			"keys": Bcs.vector(K),
			"values": Bcs.vector(V),
		}
	);
}

// 要序列化VecMap,我们可以使用:
VecMap(Bcs.string(), Bcs.string())
	.serialize({
		"keys": ['key1', 'key2', 'key3'],
		"values": ['value1', 'value2', 'value3'],
	})
	.toBytes();

转换

如果您使用的格式与BCS序列化所需的格式不同,您可以使用transform API来在您应用程序中使用的类型和序列化所需的类型之间进行映射。

Move代码中使用的address类型是一个很好的例子。在许多情况下,您可能会想将地址表示为十六进制字符串,但BCS序列化格式的地址是一个32字节的数组。为了处理这种情况,您可以使用transform API在两种格式之间进行映射:

final Address = Bcs.bytes(32).transform(
	input: (val) => fromHEX(val.toString()),
	output: (val) => toHEX(val),
);

final serialized = Address.serialize('0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef').toBytes();
final parsed = Address.parse(serialized);

序列化字节的格式

当您调用serialize方法时,您将获得一个SerializedBcs实例。此包装器保留了序列化字节的类型信息,并可以用于获取各种格式的原始数据。

final serializedString = Bcs.string().serialize('this is a string');

// SerializedBcs.toBytes() 返回一个 Uint8List
final bytes = serializedString.toBytes();

// 您可以获取编码为十六进制、base64或base58的序列化字节
final hex = serializedString.toHex();
final base64 = serializedString.toBase64();
final base58 = serializedString.toBase58();

// 要从字节解析BCS值,字节需要是一个Uint8List
final str1 = Bcs.string().parse(bytes);

// 如果您的数据编码为字符串,您需要先将其转换为Uint8List
final str2 = Bcs.string().parse(fromHEX(hex));
final str3 = Bcs.string().parse(fromB64(base64));
final str4 = Bcs.string().parse(fromB58(base58));

expect((str1 == str2) == (str3 == str4), true);

更多关于Flutter插件bcs的使用方法的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter插件bcs的使用方法的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,尽管bcs插件的具体功能未明确定义,但我们可以基于插件名进行一些合理的猜测,并展示如何在Flutter项目中集成和使用一个假设的插件。由于bcs可能代表某种二进制通信或数据序列化协议(例如BCS - Binary Communication Standard,仅为假设),以下示例将展示如何集成和使用一个假设的Flutter插件,该插件可能用于二进制数据的处理或通信。

假设的bcs插件使用示例

  1. 添加插件依赖

首先,我们需要在pubspec.yaml文件中添加对bcs插件的依赖(请注意,这里的bcs是一个假设的插件名,实际使用时需要替换为真实插件名,如果它存在的话)。

dependencies:
  flutter:
    sdk: flutter
  bcs: ^0.0.1  # 假设的版本号

然后运行flutter pub get来安装依赖。

  1. 导入插件并使用

接下来,在Dart文件中导入该插件,并展示如何使用它(以下代码为假设示例,实际使用需根据插件的真实API进行调整)。

import 'package:flutter/material.dart';
import 'package:bcs/bcs.dart';  // 假设的导入路径

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String result = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BCS Plugin Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Result:',
            ),
            Text(
              result,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                // 假设的BCS插件功能:编码和解码二进制数据
                String originalData = "Hello, Flutter!";
                List<int> encodedData = await BcsEncoder().encode(originalData);
                String decodedData = await BcsDecoder().decode(encodedData);

                setState(() {
                  result = 'Encoded: $encodedData\nDecoded: $decodedData';
                });
              },
              child: Text('Encode and Decode'),
            ),
          ],
        ),
      ),
    );
  }
}

// 假设的BcsEncoder和BcsDecoder类
class BcsEncoder {
  Future<List<int>> encode(String data) async {
    // 这里应该是插件提供的二进制编码逻辑
    // 由于是假设,这里仅返回一个简单的字节列表作为示例
    return Uint8List.fromList(data.codeUnits);
  }
}

class BcsDecoder {
  Future<String> decode(List<int> data) async {
    // 这里应该是插件提供的二进制解码逻辑
    // 由于是假设,这里仅将字节列表转换回字符串作为示例
    return String.fromCharCodes(data);
  }
}

注意事项

  • 上述代码中的BcsEncoderBcsDecoder类是为了演示目的而假设的。在实际使用中,这些类将由bcs插件提供,并具有实际的二进制编码和解码功能。
  • 如果bcs插件实际上存在并且有不同的API,你需要根据插件的文档来调整代码。
  • 如果bcs插件不存在,你可能需要寻找其他实现类似功能的插件,或者自己编写相关功能。

由于bcs插件的具体功能和API未知,上述示例仅用于展示如何在Flutter项目中集成和使用一个假设的插件。在实际项目中,你需要根据插件的真实文档和API进行调整。

回到顶部