private IEnumerable <IErlObject> enumErlResponseTuple(ErlTuple tuple, bool singleKey) { if (singleKey) { foreach (var elm in tuple) { yield return(elm); } yield break; } for (var i = 0; i < tuple.Count; i++) { var elm = tuple[i]; if (i == 1) { var ktuple = elm as ErlTuple; if (ktuple == null) { throw new ErlDataAccessException(StringConsts.ERL_DS_INTERNAL_MAPPING_ERROR + "key tuple is missing"); } foreach (var keye in ktuple) { yield return(keye); } continue; } yield return(elm); } }
private void sendRpcReply(ErlPid from, ErlRef eref, IErlObject reply) { if (from.Empty) { return; } Node.Send(from, ErlTuple.Create(eref, reply)); }
private void threadSpinCore() { // For Erlang I/O protocol see: // http://erlang.org/doc/apps/stdlib/io_protocol.html var patterns = new ErlPatternMatcher { { "{'$gen_call', {~v::pid(), ~v::ref()}, {call, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(P, R, M, F, A, G), (_p, _t, b, a) => rpcCall( b.Cast <ErlPid>(P), b.Cast <ErlRef>(R), b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), b[G]) }, { "{'$gen_cast', {cast, ~v::atom(), ~v::atom(), ~v::list(), ~v}}".ErlArgs(M, F, A, G), (_p, _t, b, a) => rpcCall( ErlPid.Null, ErlRef.Null, b.Cast <ErlAtom>(M), b.Cast <ErlAtom>(F), b.Cast <ErlList>(A), b[G]) }, { "{_, {~v::pid(), ~v::ref()}, _Cmd}".ErlArgs(P, R), (_p, _t, b, a) => ErlTuple.Create(b[P], b[R], ErlTuple.Create(ConstAtoms.Error, ConstAtoms.Unsupported)) }, }; while (m_Active) { Tuple <IErlObject, int> res = Self.ReceiveMatch(patterns, 1500); switch (res.Item2) { case -2: /* timeout */ break; case -1: /* no match */ App.Log.Write(Log.MessageType.Warning, StringConsts.ERL_INVALID_RPC_REQUEST_ERROR, res.Item1.ToString()); break; default: if (res.Item1 == null) { break; } var t = (ErlTuple)res.Item1; var pid = t.Cast <ErlPid>(0); var eref = t.Cast <ErlRef>(1); var reply = t[2]; sendRpcReply(pid, eref, reply); break; } } App.Log.Write( Log.MessageType.Info, StringConsts.ERL_STOPPING_SERVER.Args(Node.NodeName, "RPC")); m_Thread = null; }
public void ErlFormatTest() { var tests = new Dictionary <string, ErlList> { { "abc 10.5", new ErlList("abc ~w.~w", 10, 5) }, { "xx 8", new ErlList("xx ~i~w", 12, 8) }, { "~z", new ErlList("~~z", 16) }, { "a 16", new ErlList("~c ~w", (byte)'a', 16) }, { "xyz 12\n", new ErlList("xyz ~10.6.B~n", 12) }, { "x~y21", new ErlList("x~~y~w1", 2) }, { "{ok, A}", new ErlList("{ok, ~v}", "A") }, { "{ok, A}.", new ErlList("{ok, ~v}.", new ErlAtom("A")) }, { "{ok, A} ", new ErlList("{ok, ~v} ", new ErlString("A")) }, { "{ok, A} ", new ErlList("{ok, ~v} ", new ErlVar("A")) }, { "{ok, A::a()}", new ErlList("{ok, ~v::a()}", new ErlVar("A", ErlTypeOrder.ErlLong)) }, { "{ok, A::int()}", new ErlList("{ok, ~v}", new ErlVar("A", ErlTypeOrder.ErlLong)) }, }; foreach (var t in tests) { Assert.AreEqual(t.Key, ErlObject.Format(t.Value), "Error in test: {0} <- format({1})".Args(t.Key, t.Value.ToString())); } var failTests = new List <ErlList> { new ErlList("abc ~w.~w"), new ErlList("xx ~i~w", 12), new ErlList("~y", 12), }; foreach (var t in failTests) { Assert.Throws <ErlException>( () => ErlObject.Format(t), "Errorneously formatted term: {0}".Args(t)); } var V = new ErlVar("V", ErlTypeOrder.ErlLong); var expected = new ErlTuple(new ErlAtom("ok"), V).ToString(); Assert.AreEqual(expected, "{ok, V::int()}".ToErlObject().ToString()); Assert.AreEqual(expected, "{ok, ~w}".ToErlObject(V).ToString()); }
/// <summary> /// Maps ErlRow to CLR row supplied by schema, either Dynamic or TypedRow /// </summary> public Row ErlTupleToRow(string schemaName, ErlTuple tuple, Schema schema) { var singleKey = schema.ExtraData[SCHEMA_KEY_COUNT].AsInt(0) < 2; var row = Row.MakeRow(schema, schema.TypedRowType); var i = -1; foreach (var elm in enumErlResponseTuple(tuple, singleKey)) { i++; if (i == 0) { var thisname = tuple[0].ValueAsString; if (!schemaName.EqualsOrdSenseCase(thisname)) { throw new ErlDataAccessException(StringConsts.ERL_DS_CRUD_RESP_SCH_MISMATCH_ERROR.Args(thisname, schemaName)); } continue; } //map fields now if (i - 1 >= schema.FieldCount) { throw new ErlDataAccessException(StringConsts.ERL_DS_CRUD_RESP_SCH_FLD_COUNT_ERROR.Args(schemaName, schema.Name)); } var fdef = schema[i - 1]; var atr = fdef[m_Store.TargetName]; var erlType = atr.BackendType; if (erlType.IsNullOrWhiteSpace()) { throw new ErlDataAccessException(StringConsts.ERL_DS_INTERNAL_MAPPING_ERROR + "fielddef('{0}') has no backend type".Args(fdef.Name)); } var clrValue = ErlToClrValue(elm, schema, fdef, m_Store.TargetName, tuple); row.SetFieldValue(fdef, clrValue); } return(row); }
private IErlObject rpcCall(ErlPid from, ErlRef eref, ErlAtom mod, ErlAtom fun, ErlList args, IErlObject groupLeader) { // We spawn a new task, so that RPC calls wouldn't block the RPC server thread Task.Factory.StartNew(() => { var type = Type.GetType(mod); if (type == null) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, "unknown type: {0}".Args(mod))); return; } // TODO: add LRU caching //var method = type.GetMethod(fun.Value, BindingFlags.Static | BindingFlags.Public); string methodName = fun.Value; if (args.Count == 0) { var pi = type.GetProperty(fun, BindingFlags.Static | BindingFlags.Public); if (pi != null) { try { var result = pi.GetValue(null, null); sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Ok, result.ToErlObject())); } catch (Exception e) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, new ErlString(e.Message))); }; return; } } var mi = type.GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(m => m.Name == methodName && m.GetParameters().Count() == args.Count) .FirstOrDefault(); if (mi == null) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, "unknown method: {0}".Args(fun))); return; } var pars = mi.GetParameters(); var margs = new object[pars.Length]; for (int i = 0; i < pars.Length; i++) { var par = pars[i]; var val = args[i]; margs[i] = val.AsType(par.ParameterType); } try { var result = mi.Invoke(type, margs); sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Ok, result.ToErlObject())); } catch (Exception e) { sendRpcReply(from, eref, ErlTuple.Create(ConstAtoms.Error, new ErlString(e.Message))); } }); return((IErlObject)null); }
public void ErlTupleTest() { var l = new ErlTuple("test", 1, 1.1, true, (byte)255, 'x', new ErlAtom("a")); var r = new ErlTuple("test", 1, 1.1, true, (byte)255, 'x', new ErlAtom("a")); Assert.AreEqual(7, l.Count); Assert.AreEqual(ErlTypeOrder.ErlString, l[0].TypeOrder); Assert.AreEqual("test", l[0].ValueAsString); Assert.AreEqual(ErlTypeOrder.ErlLong, l[1].TypeOrder); Assert.AreEqual(1, l[1].ValueAsInt); Assert.AreEqual(ErlTypeOrder.ErlDouble, l[2].TypeOrder); Assert.AreEqual(1.1, l[2].ValueAsDouble); Assert.AreEqual(ErlTypeOrder.ErlBoolean, l[3].TypeOrder); Assert.AreEqual(true, l[3].ValueAsBool); Assert.AreEqual(ErlTypeOrder.ErlByte, l[4].TypeOrder); Assert.AreEqual(255, l[4].ValueAsInt); Assert.AreEqual(ErlTypeOrder.ErlByte, l[5].TypeOrder); Assert.AreEqual('x', l[5].ValueAsChar); Assert.AreEqual(ErlTypeOrder.ErlAtom, l[6].TypeOrder); Assert.AreEqual("a", l[6].ValueAsString); Assert.IsTrue(l.Matches(r)); Assert.AreEqual(new ErlVarBind(), l.Match(r)); Assert.AreEqual(l, r); Assert.IsTrue(l.Equals(r)); Assert.AreEqual("{\"test\",1,1.1,true,255,120,a}", l.ToString()); Assert.IsFalse(l.IsScalar); Assert.AreEqual(ErlTypeOrder.ErlTuple, l.TypeOrder); IErlObject temp = null; Assert.IsFalse(l.Subst(ref temp, new ErlVarBind())); Assert.AreEqual(1, l.Visit(0, (acc, o) => acc + (o is ErlAtom ? 1 : 0))); Assert.IsTrue(new ErlTuple(new ErlVar(X), true, 1).Subst(ref temp, new ErlVarBind { { X, new ErlLong(10) } })); Assert.AreEqual("{10,true,1}", temp.ToString()); var d = new DateTime(2013, 1, 2); var ts = new TimeSpan(1, 2, 3); Assert.DoesNotThrow(() => { var x = l.ValueAsObject; }); Assert.AreEqual(1, new ErlList("1")[0].ValueAsInt); Assert.AreEqual(1, new ErlList("1")[0].ValueAsLong); Assert.AreEqual(1, new ErlList("1")[0].ValueAsDecimal); Assert.AreEqual(d, new ErlList(d.ToString())[0].ValueAsDateTime); Assert.AreEqual(ts, new ErlList(ts.ToString())[0].ValueAsTimeSpan); Assert.AreEqual(1.0, new ErlList("1.0")[0].ValueAsDouble); Assert.AreEqual("a", new ErlList("a")[0].ValueAsString); Assert.IsTrue(new ErlList("true")[0].ValueAsBool); Assert.IsFalse(new ErlList("xxxx")[0].ValueAsBool); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsInt; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsLong; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsDecimal; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsDateTime; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsTimeSpan; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsDouble; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsString; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsBool; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsChar; }); Assert.Throws <ErlIncompatibleTypesException>(() => { var x = l.ValueAsByteArray; }); List <IErlObject> s = l; Assert.AreEqual(l.Value, s); Assert.IsFalse(new ErlList(1, 1.0, "a").Equals(new ErlTuple(1, 1.0, "a"))); Assert.IsFalse(new ErlList(1, 1.0, "a") == new ErlTuple(1, 1.0, "a")); Assert.IsTrue(new ErlList(1, 1.0, "a") == new ErlList(1, 1.0, "a")); }
public void ErlTermSerializeTest() { { var b = new byte[] { 131, 100, 0, 3, 97, 98, 99 }; var t = new ErlAtom("abc"); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 109, 0, 0, 0, 3, 1, 2, 3 }; var t = new ErlBinary(new byte[] { 1, 2, 3 }); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b1 = new byte[] { 131, 100, 0, 4, 116, 114, 117, 101 }; var t1 = new ErlBoolean(true); var os1 = new ErlOutputStream(t1); Aver.IsTrue(b1.MemBufferEquals(os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray())); var es1 = new ErlInputStream(b1); Aver.AreEqual(t1, es1.Read()); var b2 = new byte[] { 131, 100, 0, 5, 102, 97, 108, 115, 101 }; var t2 = new ErlBoolean(false); var os2 = new ErlOutputStream(t2); Aver.IsTrue(b2.MemBufferEquals(os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray())); var es2 = new ErlInputStream(b2); Aver.AreEqual(t2, es2.Read()); } { var b = new byte[] { 131, 97, 127 }; var t = new ErlByte(127); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 70, 64, 36, 62, 249, 219, 34, 208, 229 }; var t = new ErlDouble(10.123); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 108, 0, 0, 0, 2, 107, 0, 1, 1, 107, 0, 1, 2, 106 }; var t = new ErlList(new ErlList(1), new ErlList(2)); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 108, 0, 0, 0, 2, 108, 0, 0, 0, 2, 97, 1, 107, 0, 1, 2, 106, 107, 0, 1, 3, 106 }; var t = new ErlList(new ErlList(1, new ErlList(2)), new ErlList(3)); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 108, 0, 0, 0, 3, 97, 1, 70, 64, 36, 61, 112, 163, 215, 10, 61, 108, 0, 0, 0, 2, 100, 0, 4, 116, 114, 117, 101, 107, 0, 1, 97, 106, 106 }; var t = new ErlList(1, 10.12, new ErlList(true, "a")); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 108, 0, 0, 0, 3, 97, 23, 97, 4, 104, 1, 108, 0, 0, 0, 1, 104, 2, 109, 0, 0, 0, 5, 101, 118, 101, 110, 116, 104, 1, 108, 0, 0, 0, 2, 104, 2, 109, 0, 0, 0, 10, 102, 108, 101, 101, 116, 95, 104, 97, 115, 104, 109, 0, 0, 0, 36, 97, 54, 97, 50, 50, 100, 49, 52, 45, 56, 52, 56, 51, 45, 52, 49, 102, 99, 45, 97, 52, 54, 98, 45, 50, 56, 51, 98, 57, 55, 55, 55, 99, 50, 97, 50, 104, 2, 109, 0, 0, 0, 4, 116, 121, 112, 101, 109, 0, 0, 0, 13, 102, 108, 101, 101, 116, 95, 99, 104, 97, 110, 103, 101, 100, 106, 106, 106 }; var t = ErlObject.Parse("[23,4,{[{<<\"event\">>," + "{[{<<\"fleet_hash\">>,<<\"a6a22d14-8483-41fc-a46b-283b9777c2a2\">>}," + "{<<\"type\">>,<<\"fleet_changed\">>}]}}]}]"); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b1 = new byte[] { 131, 98, 255, 255, 255, 251 }; var t1 = new ErlLong(-5); var os1 = new ErlOutputStream(t1); Aver.IsTrue(b1.MemBufferEquals(os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray())); var es1 = new ErlInputStream(b1); Aver.AreEqual(t1, es1.Read()); var b2 = new byte[] { 131, 97, 5 }; var t2 = new ErlLong(5); var os2 = new ErlOutputStream(t2); Aver.IsTrue(b2.MemBufferEquals(os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray())); var es2 = new ErlInputStream(b2); Aver.AreEqual(t2, es2.Read()); var b3 = new byte[] { 131, 98, 0, 16, 0, 0 }; var t3 = new ErlLong(1024 * 1024); var os3 = new ErlOutputStream(t3); Aver.IsTrue(b3.MemBufferEquals(os3.GetBuffer().TakeWhile((_, i) => i < b3.Length).ToArray())); var es3 = new ErlInputStream(b3); Aver.AreEqual(t3, es3.Read()); var b4 = new byte[] { 131, 110, 6, 0, 0, 0, 0, 0, 0, 4 }; var t4 = new ErlLong(1024L * 1024 * 1024 * 1024 * 4); var os4 = new ErlOutputStream(t4); Aver.IsTrue(b4.MemBufferEquals(os4.GetBuffer().TakeWhile((_, i) => i < b4.Length).ToArray())); var es4 = new ErlInputStream(b4); Aver.AreEqual(t4, es4.Read()); var b5 = new byte[] { 131, 110, 8, 1, 0, 0, 0, 0, 0, 0, 0, 128 }; var t5 = new ErlLong(1L << 63); var os5 = new ErlOutputStream(t5); Aver.IsTrue(b5.MemBufferEquals(os5.GetBuffer().TakeWhile((_, i) => i < b5.Length).ToArray())); var es5 = new ErlInputStream(b5); Aver.AreEqual(t5, es5.Read()); var b6 = new byte[] { 131, 110, 8, 1, 0, 0, 0, 0, 0, 0, 0, 128 }; var t6 = new ErlLong(-1L << 63); var os6 = new ErlOutputStream(t6); Aver.IsTrue(b6.MemBufferEquals(os6.GetBuffer().TakeWhile((_, i) => i < b6.Length).ToArray())); var es6 = new ErlInputStream(b6); Aver.AreEqual(t6, es6.Read()); var b7 = new byte[] { 131, 110, 8, 0, 255, 255, 255, 255, 255, 255, 255, 255 }; var es7 = new ErlInputStream(b7); var t7 = new ErlLong(-1); Aver.AreEqual(t7, es7.Read()); var bi7 = new byte[] { 131, 98, 255, 255, 255, 255 }; var os7 = new ErlOutputStream(t7); Aver.IsTrue(bi7.MemBufferEquals(os7.GetBuffer().TakeWhile((_, i) => i < bi7.Length).ToArray())); } { var b = new byte[] { 131, 103, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 0, 0, 0, 0, 1 }; var t = new ErlPid("b@pipit", 38, 0, 1); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 102, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 1 }; var t = new ErlPort("b@pipit", 38, 1); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 114, 0, 3, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 1, 0, 0, 0, 181, 0, 0, 0, 0, 0, 0, 0, 0 }; var t = new ErlRef("b@pipit", 181, 0, 0, 1); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 107, 0, 3, 115, 116, 114 }; var t = new ErlString("str"); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 104, 3, 97, 1, 100, 0, 1, 97, 104, 2, 97, 10, 70, 63, 241, 247, 206, 217, 22, 135, 43 }; var t = new ErlTuple(1, new ErlAtom("a"), new ErlTuple(10, 1.123)); var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 116, 0, 0, 0, 2, 100, 0, 1, 97, 97, 1, 107, 0, 3, 115, 116, 114, 70, 64, 0, 0, 0, 0, 0, 0, 0 }; var t = new ErlMap { { new ErlAtom("a"), 1.ToErlObject() }, { new ErlString("str"), new ErlDouble(2.0) } }; var os = new ErlOutputStream(t); Aver.IsTrue(b.MemBufferEquals(os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray())); var es = new ErlInputStream(b); Aver.AreEqual(t, es.Read()); } }
/// <summary> /// Convert an Erlang hierarchical term representing a schema to a Row. /// </summary> /// <param name="row">Row to update</param> /// <param name="data"> /// Data to update row with. /// The data must be in the form {SchemaName::atom, [{FieldName::atom(), Value}]}. /// </param> /// <param name="schema">Alternative schema to use in place of row.Schema</param> /// <param name="targetName">Name of the target for looking up field attributes</param> /// <param name="schemaName">Alternative name of the top-most 'SchemaName' atom used in the "data".</param> /// <param name="knownSchemas">List of known schemas to use when initializing a field a DynamicRow type.</param> public static void Update(this Row row, IErlObject data, Schema schema = null, string targetName = null, string schemaName = null, Registry<Schema> knownSchemas = null) { if (schema == null) schema = row.Schema; if (schemaName == null) schemaName = schema.Name; if (data == null) data = new ErlTuple(new ErlAtom(schemaName), new ErlList()); // Input data must be in the form: {SchemaName::atom(), [{FieldName::atom(), Value}]} // where Value can be any primitive value or a hierarchical value with another Row type. if (!checkKeyValueTuple(data) || ((ErlTuple)data)[1].TypeOrder != ErlTypeOrder.ErlList) throw new ErlDataAccessException( StringConsts.ERL_DS_CRUD_RESP_SCH_MISMATCH_ERROR.Args(data.ToString(), schema.Name)); var dataList = ((ErlTuple)data)[1] as ErlList; // Make sure that the first element of the tuple matches the schema name if (!((ErlTuple)data)[0].ValueAsString.Equals(schemaName)) throw new ErlDataAccessException( StringConsts.ERL_DS_CRUD_RESP_SCH_MISMATCH_ERROR.Args(data.ToString(), schema.Name)); // Contains a set of field names that are present in configuration var presentFieldNames = new HashSet<string>(); foreach (var item in dataList.Where(checkKeyValueTuple).Cast<ErlTuple>()) presentFieldNames.Add(item[0].ValueAsString); ErlList newList = null; foreach (var fld in schema.Where(fd => typeof(Row).IsAssignableFrom(fd.Type))) if (!presentFieldNames.Contains(fld.Name)) { if (newList == null) newList = (ErlList)dataList.Clone(); // Add: {FieldName::atom(), []} newList.Add(new ErlTuple(new ErlAtom(fld.Name), new ErlList())); } // If no new items were added to the list use current list: if (newList == null) newList = dataList; foreach (var item in newList.Where(checkKeyValueTuple).Cast<ErlTuple>()) { var name = item[0].ValueAsString; var value = item[1]; var fdef = schema[name]; var attr = fdef[targetName]; if (!attr.Visible || (attr.Metadata != null && attr.Metadata.Navigate("$readonly|$read-only|$read_only").ValueAsBool())) continue; // If this field is defined in the schema as a Row type, then we need to descend into the // value's hierarchical structure and treat it as a nested row if (typeof(Row).IsAssignableFrom(fdef.Type)) { // Get the row associated Schema chldSch; var chldRow = row[fdef.Order] as Row; // If the row has a field of Row type initialized, use its Schema value. if (chldRow != null) chldSch = chldRow.Schema; else { // Otherwise lookup the schema from the given registry if (!knownSchemas.TryGetValue(name, out chldSch)) throw new ErlDataAccessException( StringConsts.ERL_DS_SCHEMA_NOT_KNOWN_ERROR.Args(name, data.ToString())); // Construct the field's value as dynmiac row of the looked up schema type chldRow = new DynamicRow(chldSch); chldRow.ApplyDefaultFieldValues(); row[fdef.Order] = chldRow; } if (value.TypeOrder != ErlTypeOrder.ErlList) throw new ErlDataAccessException( StringConsts.ERL_DS_SCHEMA_INVALID_VALUE_ERROR.Args(chldSch.Name, value)); // Recursively update the field's value from given data by using the field's schema: chldRow.Update(item, chldSch, targetName, knownSchemas: knownSchemas); } else { // This is a primitive value type var clr = SchemaMap.ErlToClrValue(value, schema, fdef, null, data); row.SetFieldValue(fdef, clr); } } }
/// <summary> /// Convert an Erlang hierarchical term representing a schema to a Row. /// </summary> /// <param name="row">Row to update</param> /// <param name="data"> /// Data to update row with. /// The data must be in the form {SchemaName::atom, [{FieldName::atom(), Value}]}. /// </param> /// <param name="schema">Alternative schema to use in place of row.Schema</param> /// <param name="targetName">Name of the target for looking up field attributes</param> /// <param name="schemaName">Alternative name of the top-most 'SchemaName' atom used in the "data".</param> /// <param name="knownSchemas">List of known schemas to use when initializing a field a DynamicRow type.</param> public static void Update(this Row row, IErlObject data, Schema schema = null, string targetName = null, string schemaName = null, Registry <Schema> knownSchemas = null) { if (schema == null) { schema = row.Schema; } if (schemaName == null) { schemaName = schema.Name; } if (data == null) { data = new ErlTuple(new ErlAtom(schemaName), new ErlList()); } // Input data must be in the form: {SchemaName::atom(), [{FieldName::atom(), Value}]} // where Value can be any primitive value or a hierarchical value with another Row type. if (!checkKeyValueTuple(data) || ((ErlTuple)data)[1].TypeOrder != ErlTypeOrder.ErlList) { throw new ErlDataAccessException( StringConsts.ERL_DS_CRUD_RESP_SCH_MISMATCH_ERROR.Args(data.ToString(), schema.Name)); } var dataList = ((ErlTuple)data)[1] as ErlList; // Make sure that the first element of the tuple matches the schema name if (!((ErlTuple)data)[0].ValueAsString.Equals(schemaName)) { throw new ErlDataAccessException( StringConsts.ERL_DS_CRUD_RESP_SCH_MISMATCH_ERROR.Args(data.ToString(), schema.Name)); } // Contains a set of field names that are present in configuration var presentFieldNames = new HashSet <string>(); foreach (var item in dataList.Where(checkKeyValueTuple).Cast <ErlTuple>()) { presentFieldNames.Add(item[0].ValueAsString); } ErlList newList = null; foreach (var fld in schema.Where(fd => typeof(Row).IsAssignableFrom(fd.Type))) { if (!presentFieldNames.Contains(fld.Name)) { if (newList == null) { newList = (ErlList)dataList.Clone(); } // Add: {FieldName::atom(), []} newList.Add(new ErlTuple(new ErlAtom(fld.Name), new ErlList())); } } // If no new items were added to the list use current list: if (newList == null) { newList = dataList; } foreach (var item in newList.Where(checkKeyValueTuple).Cast <ErlTuple>()) { var name = item[0].ValueAsString; var value = item[1]; var fdef = schema[name]; var attr = fdef[targetName]; if (!attr.Visible || (attr.Metadata != null && attr.Metadata.Navigate("$readonly|$read-only|$read_only").ValueAsBool())) { continue; } // If this field is defined in the schema as a Row type, then we need to descend into the // value's hierarchical structure and treat it as a nested row if (typeof(Row).IsAssignableFrom(fdef.Type)) { // Get the row associated Schema chldSch; var chldRow = row[fdef.Order] as Row; // If the row has a field of Row type initialized, use its Schema value. if (chldRow != null) { chldSch = chldRow.Schema; } else { // Otherwise lookup the schema from the given registry if (!knownSchemas.TryGetValue(name, out chldSch)) { throw new ErlDataAccessException( StringConsts.ERL_DS_SCHEMA_NOT_KNOWN_ERROR.Args(name, data.ToString())); } // Construct the field's value as dynmiac row of the looked up schema type chldRow = new DynamicRow(chldSch); chldRow.ApplyDefaultFieldValues(); row[fdef.Order] = chldRow; } if (value.TypeOrder != ErlTypeOrder.ErlList) { throw new ErlDataAccessException( StringConsts.ERL_DS_SCHEMA_INVALID_VALUE_ERROR.Args(chldSch.Name, value)); } // Recursively update the field's value from given data by using the field's schema: chldRow.Update(item, chldSch, targetName, knownSchemas: knownSchemas); } else { // This is a primitive value type var clr = SchemaMap.ErlToClrValue(value, schema, fdef, null, data); row.SetFieldValue(fdef, clr); } } }
/// <summary> /// Compile a string fmt into an Erlang term /// </summary> internal static IErlObject Parse( string fmt, ref int pos, ref int argc, params object[] args) { var items = new List<IErlObject>(); IErlObject result = null; pos = skipWSAndComments(fmt, pos); if (pos < fmt.Length) { switch (fmt[pos++]) { case '{': if (State.Ok != pTuple(fmt, ref pos, ref items, ref argc, args)) throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "tuple", pos); result = new ErlTuple(items, false); break; case '[': if (fmt[pos] == ']') { result = new ErlList(); pos++; break; } else if (State.Ok == pList(fmt, ref pos, ref items, ref argc, args)) { result = new ErlList(items, false); break; } throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "list", pos); case '$': /* char-value? */ result = new ErlByte(Convert.ToByte(fmt[pos++])); break; case '~': if (State.Ok != pFormat(fmt, ref pos, ref items, ref argc, args)) throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "term", pos); result = items[0]; break; default: char c = fmt[--pos]; if (char.IsLower(c)) { /* atom ? */ string s = pAtom(fmt, ref pos); result = createAtom(s); } else if (char.IsUpper(c) || c == '_') { result = pVariable(fmt, ref pos); } else if (char.IsDigit(c) || c == '-') { /* integer/float ? */ string s = pDigit(fmt, ref pos); if (s.IndexOf('.') < 0) result = new ErlLong(long.Parse(s, CultureInfo.InvariantCulture)); else result = new ErlDouble(double.Parse(s, CultureInfo.InvariantCulture)); } else if (c == '"') { /* string ? */ string s = pString(fmt, ref pos); result = new ErlString(s); } else if (c == '\'') { /* quoted atom ? */ string s = pQuotedAtom(fmt, ref pos); result = createAtom(s); } break; } } if (result == null) throw new ErlException(StringConsts.ERL_INVALID_VALUE_ERROR.Args(fmt)); return result; }
/// <summary> /// Compile a string fmt into an Erlang term /// </summary> internal static IErlObject Parse( string fmt, ref int pos, ref int argc, params object[] args) { var items = new List <IErlObject>(); IErlObject result = null; pos = skipWSAndComments(fmt, pos); if (pos < fmt.Length) { switch (fmt[pos++]) { case '{': if (State.Ok != pTuple(fmt, ref pos, ref items, ref argc, args)) { throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "tuple", pos); } result = new ErlTuple(items, false); break; case '[': if (fmt[pos] == ']') { result = new ErlList(); pos++; break; } else if (State.Ok == pList(fmt, ref pos, ref items, ref argc, args)) { result = new ErlList(items, false); break; } throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "list", pos); case '$': /* char-value? */ result = new ErlByte(Convert.ToByte(fmt[pos++])); break; case '~': if (State.Ok != pFormat(fmt, ref pos, ref items, ref argc, args)) { throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "term", pos); } result = items[0]; break; default: char c = fmt[--pos]; if (char.IsLower(c)) { /* atom ? */ string s = pAtom(fmt, ref pos); result = createAtom(s); } else if (char.IsUpper(c) || c == '_') { result = pVariable(fmt, ref pos); } else if (char.IsDigit(c) || c == '-') { /* integer/float ? */ string s = pDigit(fmt, ref pos); if (s.IndexOf('.') < 0) { result = new ErlLong(long.Parse(s, CultureInfo.InvariantCulture)); } else { result = new ErlDouble(double.Parse(s, CultureInfo.InvariantCulture)); } } else if (c == '"') { /* string ? */ string s = pString(fmt, ref pos); result = new ErlString(s); } else if (c == '\'') { /* quoted atom ? */ string s = pQuotedAtom(fmt, ref pos); result = createAtom(s); } break; } } if (result == null) { throw new ErlException(StringConsts.ERL_INVALID_VALUE_ERROR.Args(fmt)); } return(result); }
/// <summary> /// Converts CLR row data into ErlTuple /// </summary> public ErlTuple RowToErlTuple(Row row, bool keysOnly = false) { var result = new ErlTuple(); result.Add(new ErlAtom(row.Schema.Name)); var keys = new List <IErlObject>(); foreach (var def in row.Schema) { var atr = def[m_Store.TargetName]; if (keysOnly && !atr.Key) { break; } if (keys != null && !atr.Key) { if (keys.Count > 1) { result.Add(new ErlTuple(keys, false)); } else { foreach (var key in keys) { result.Add(key); } } keys = null; } IErlObject erlValue = ErlAtom.Undefined; var clrValue = row.GetFieldValue(def); if (clrValue != null) { erlValue = ClrToErlValue(atr.BackendType, clrValue); } if (keys != null) { keys.Add(erlValue); } else { result.Add(erlValue); } } if (keys != null) { if (keys.Count > 1) { result.Add(new ErlTuple(keys, false)); } else { foreach (var key in keys) { result.Add(key); } } } return(result); }
/// <summary> /// Compile a string fmt into an Erlang term /// </summary> internal static IErlObject Parse( string fmt, ref int pos, ref int argc, params object[] args) { var items = new List<IErlObject>(); IErlObject result = null; pos = skipWSAndComments(fmt, pos); if (pos < fmt.Length) { switch (fmt[pos++]) { case '{': if (State.Ok != pTuple(fmt, ref pos, ref items, ref argc, args)) throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "tuple", pos); result = new ErlTuple(items, false); break; case '[': if (fmt[pos] == ']') { result = new ErlList(); pos++; break; } else if (State.Ok == pList(fmt, ref pos, ref items, ref argc, args)) { result = new ErlList(items, false); break; } throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "list", pos); case '<': if (pos < fmt.Length - 1 && fmt[pos] == '<') { var i = ++pos; var str = fmt[i] == '"'; if (str) pos++; for (; i < fmt.Length && fmt[i - 1] != '>' && fmt[i] != '>'; ++i); if (i == fmt.Length) break; var end = ++i - (str ? 3 : 2); var len = end - pos + 1; byte[] bytes; if (str) { var cnt = Encoding.UTF8.GetByteCount(fmt.ToCharArray(), pos, len); bytes = new byte[cnt]; Encoding.UTF8.GetBytes(fmt, pos, len, bytes, 0); } else { var beg = pos - 2; bytes = fmt.Substring(pos, len) .Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries) .Select(s => { var n = int.Parse(s); if (n < 0 || n > 255) throw new ErlException ("Invalid binary in format string: {0}".Args(fmt.Substring(beg, len+4))); return (byte)n; }) .ToArray(); } result = new ErlBinary(bytes, 0, bytes.Length); pos = i+1; } break; case '$': /* char-value? */ result = new ErlByte(Convert.ToByte(fmt[pos++])); break; case '~': if (State.Ok != pFormat(fmt, ref pos, ref items, ref argc, args)) throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "term", pos); result = items[0]; break; default: char c = fmt[--pos]; if (char.IsLower(c)) { /* atom ? */ string s = pAtom(fmt, ref pos); result = createAtom(s); } else if (char.IsUpper(c) || c == '_') { result = pVariable(fmt, ref pos); } else if (char.IsDigit(c) || c == '-') { /* integer/float ? */ string s = pDigit(fmt, ref pos); if (s.IndexOf('.') < 0) result = new ErlLong(long.Parse(s, CultureInfo.InvariantCulture)); else result = new ErlDouble(double.Parse(s, CultureInfo.InvariantCulture)); } else if (c == '"') { /* string ? */ string s = pString(fmt, ref pos); result = new ErlString(s); } else if (c == '\'') { /* quoted atom ? */ string s = pQuotedAtom(fmt, ref pos); result = createAtom(s); } break; } } if (result == null) throw new ErlException(StringConsts.ERL_INVALID_VALUE_ERROR.Args(fmt)); return result; }
/// <summary> /// Maps ErlRow to CLR row supplied by schema, either Dynamic or TypedRow /// </summary> public Row ErlTupleToRow(string schemaName, ErlTuple tuple, Schema schema) { var singleKey = schema.ExtraData[SCHEMA_KEY_COUNT].AsInt(0) < 2; var row = Row.MakeRow(schema, schema.TypedRowType); var i = -1; foreach (var elm in enumErlResponseTuple(tuple, singleKey)) { i++; if (i == 0) { var thisname = tuple[0].ValueAsString; if (!schemaName.EqualsOrdSenseCase(thisname)) { throw new ErlDataAccessException(StringConsts.ERL_DS_CRUD_RESPONSE_SCHEMA_MISMATCH_ERROR.Args(thisname, schemaName)); } continue; } //map fields now if (i - 1 >= schema.FieldCount) { throw new ErlDataAccessException(StringConsts.ERL_DS_CRUD_RESPONSE_SCHEMA_FLD_COUNT_MISMATCH_ERROR.Args(schemaName, schema.Name)); } var fdef = schema[i - 1]; var atr = fdef[m_Store.TargetName]; var erlType = atr.BackendType; if (erlType.IsNullOrWhiteSpace()) { throw new ErlDataAccessException(StringConsts.ERL_DS_INTERNAL_MAPPING_ERROR + "fielddef('{0}') has no backend type".Args(fdef.Name)); } if (elm.IsNull()) { row.SetFieldValue(fdef, null); continue; } Tuple <Type, Func <IErlObject, object> > mapping; if (ERL_TO_CLR_TYPEMAP.TryGetValue(erlType, out mapping)) { object clrValue = null; try { clrValue = mapping.Item2(elm); } catch (Exception error) { App.Log.Write(new Log.Message { Type = Log.MessageType.TraceErl, Topic = CoreConsts.ERLANG_TOPIC, From = "SchemaMap.ErlTupleToRow({0})".Args(schemaName), Text = "Error converting element '{0}'->'{1}': {2}".Args(erlType, elm.GetType(), error.ToMessageWithType()), Exception = error }); throw; } row.SetFieldValue(fdef, clrValue); } else { throw new ErlDataAccessException(StringConsts.ERL_DS_INTERNAL_MAPPING_ERROR + "erltype'{0}' not matched in the dict".Args(erlType)); } } return(row); }
public void ErlTermSerializeTest() { { var b = new byte[] { 131, 100, 0, 3, 97, 98, 99 }; var t = new ErlAtom("abc"); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 109, 0, 0, 0, 3, 1, 2, 3 }; var t = new ErlBinary(new byte[] { 1, 2, 3 }); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b1 = new byte[] { 131, 100, 0, 4, 116, 114, 117, 101 }; var t1 = new ErlBoolean(true); var os1 = new ErlOutputStream(t1); Assert.AreEqual(b1, os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray()); var es1 = new ErlInputStream(b1); Assert.AreEqual(t1, es1.Read()); var b2 = new byte[] { 131, 100, 0, 5, 102, 97, 108, 115, 101 }; var t2 = new ErlBoolean(false); var os2 = new ErlOutputStream(t2); Assert.AreEqual(b2, os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray()); var es2 = new ErlInputStream(b2); Assert.AreEqual(t2, es2.Read()); } { var b = new byte[] { 131, 97, 127 }; var t = new ErlByte(127); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 70, 64, 36, 62, 249, 219, 34, 208, 229 }; var t = new ErlDouble(10.123); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 108, 0, 0, 0, 3, 97, 1, 70, 64, 36, 61, 112, 163, 215, 10, 61, 108, 0, 0, 0, 2, 100, 0, 4, 116, 114, 117, 101, 107, 0, 1, 97, 106, 106 }; var t = new ErlList(1, 10.12, new ErlList(true, "a")); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b1 = new byte[] { 131, 98, 255, 255, 255, 251 }; var t1 = new ErlLong(-5); var os1 = new ErlOutputStream(t1); Assert.AreEqual(b1, os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray()); var es1 = new ErlInputStream(b1); Assert.AreEqual(t1, es1.Read()); var b2 = new byte[] { 131, 97, 5 }; var t2 = new ErlLong(5); var os2 = new ErlOutputStream(t2); Assert.AreEqual(b2, os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray()); var es2 = new ErlInputStream(b2); Assert.AreEqual(t2, es2.Read()); var b3 = new byte[] { 131, 98, 0, 16, 0, 0 }; var t3 = new ErlLong(1024 * 1024); var os3 = new ErlOutputStream(t3); Assert.AreEqual(b3, os3.GetBuffer().TakeWhile((_, i) => i < b3.Length).ToArray()); var es3 = new ErlInputStream(b3); Assert.AreEqual(t3, es3.Read()); var b4 = new byte[] { 131, 110, 6, 0, 0, 0, 0, 0, 0, 4 }; var t4 = new ErlLong(1024L * 1024 * 1024 * 1024 * 4); var os4 = new ErlOutputStream(t4); Assert.AreEqual(b4, os4.GetBuffer().TakeWhile((_, i) => i < b4.Length).ToArray()); var es4 = new ErlInputStream(b4); Assert.AreEqual(t4, es4.Read()); var b5 = new byte[] { 131, 110, 8, 1, 0, 0, 0, 0, 0, 0, 0, 128 }; var t5 = new ErlLong(1L << 63); var os5 = new ErlOutputStream(t5); Assert.AreEqual(b5, os5.GetBuffer().TakeWhile((_, i) => i < b5.Length).ToArray()); var es5 = new ErlInputStream(b5); Assert.AreEqual(t5, es5.Read()); var b6 = new byte[] { 131, 110, 8, 1, 0, 0, 0, 0, 0, 0, 0, 128 }; var t6 = new ErlLong(-1L << 63); var os6 = new ErlOutputStream(t6); Assert.AreEqual(b6, os6.GetBuffer().TakeWhile((_, i) => i < b6.Length).ToArray()); var es6 = new ErlInputStream(b6); Assert.AreEqual(t6, es6.Read()); var b7 = new byte[] { 131, 110, 8, 0, 255, 255, 255, 255, 255, 255, 255, 255 }; var es7 = new ErlInputStream(b7); var t7 = new ErlLong(-1); Assert.AreEqual(t7, es7.Read()); var bi7 = new byte[] { 131, 98, 255, 255, 255, 255 }; var os7 = new ErlOutputStream(t7); Assert.AreEqual(bi7, os7.GetBuffer().TakeWhile((_, i) => i < bi7.Length).ToArray()); } { var b = new byte[] { 131, 103, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 0, 0, 0, 0, 1 }; var t = new ErlPid("b@pipit", 38, 0, 1); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 102, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 1 }; var t = new ErlPort("b@pipit", 38, 1); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 114, 0, 3, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 1, 0, 0, 0, 181, 0, 0, 0, 0, 0, 0, 0, 0 }; var t = new ErlRef("b@pipit", 181, 0, 0, 1); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 107, 0, 3, 115, 116, 114 }; var t = new ErlString("str"); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } { var b = new byte[] { 131, 104, 3, 97, 1, 100, 0, 1, 97, 104, 2, 97, 10, 70, 63, 241, 247, 206, 217, 22, 135, 43 }; var t = new ErlTuple(1, new ErlAtom("a"), new ErlTuple(10, 1.123)); var os = new ErlOutputStream(t); Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray()); var es = new ErlInputStream(b); Assert.AreEqual(t, es.Read()); } }
/// <summary> /// Converts CLR row data into ErlTuple /// </summary> public ErlTuple RowToErlTuple(Row row, bool keysOnly = false) { var result = new ErlTuple(); result.Add(new ErlAtom(row.Schema.Name)); var keys = new List <IErlObject>(); foreach (var def in row.Schema) { var atr = def[m_Store.TargetName]; if (keysOnly && !atr.Key) { break; } if (keys != null && !atr.Key) { if (keys.Count > 1) { result.Add(new ErlTuple(keys, false)); } else { foreach (var key in keys) { result.Add(key); } } keys = null; } IErlObject erlValue = ErlAtom.Undefined; var clrValue = row.GetFieldValue(def); if (clrValue != null) { Func <object, IErlObject> fconv; if (!CLR_TO_ERL_TYPEMAP.TryGetValue(atr.BackendType, out fconv)) { throw new ErlDataAccessException(StringConsts.ERL_DS_INTERNAL_MAPPING_ERROR + "erltype'{0}' not matched in the dict".Args(atr.BackendType)); } erlValue = fconv(clrValue); } if (keys != null) { keys.Add(erlValue); } else { result.Add(erlValue); } } if (keys != null) { if (keys.Count > 1) { result.Add(new ErlTuple(keys, false)); } else { foreach (var key in keys) { result.Add(key); } } } return(result); }
/// <summary> /// Compile a string fmt into an Erlang term /// </summary> internal static IErlObject Parse( string fmt, ref int pos, ref int argc, params object[] args) { var items = new List <IErlObject>(); IErlObject result = null; pos = skipWSAndComments(fmt, pos); if (pos < fmt.Length) { switch (fmt[pos++]) { case '{': if (State.Ok != pTuple(fmt, ref pos, ref items, ref argc, args)) { throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "tuple", pos); } result = new ErlTuple(items, false); break; case '[': if (fmt[pos] == ']') { result = new ErlList(); pos++; break; } else if (State.Ok == pList(fmt, ref pos, ref items, ref argc, args)) { result = new ErlList(items, false); break; } throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "list", pos); case '<': if (pos < fmt.Length - 1 && fmt[pos] == '<') { var i = ++pos; var str = fmt[i] == '"'; if (str) { pos++; } for (; i < fmt.Length && fmt[i - 1] != '>' && fmt[i] != '>'; ++i) { ; } if (i == fmt.Length) { break; } var end = ++i - (str ? 3 : 2); var len = end - pos + 1; byte[] bytes; if (str) { var cnt = Encoding.UTF8.GetByteCount(fmt.ToCharArray(), pos, len); bytes = new byte[cnt]; Encoding.UTF8.GetBytes(fmt, pos, len, bytes, 0); } else { var beg = pos - 2; bytes = fmt.Substring(pos, len) .Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => { var n = int.Parse(s); if (n < 0 || n > 255) { throw new ErlException ("Invalid binary in format string: {0}".Args(fmt.Substring(beg, len + 4))); } return((byte)n); }) .ToArray(); } result = new ErlBinary(bytes, 0, bytes.Length); pos = i + 1; } break; case '$': /* char-value? */ result = new ErlByte(Convert.ToByte(fmt[pos++])); break; case '~': if (State.Ok != pFormat(fmt, ref pos, ref items, ref argc, args)) { throw new ErlException(StringConsts.ERL_PARSING_AT_ERROR, "term", pos); } result = items[0]; break; default: char c = fmt[--pos]; if (char.IsLower(c)) { /* atom ? */ string s = pAtom(fmt, ref pos); result = createAtom(s); } else if (char.IsUpper(c) || c == '_') { result = pVariable(fmt, ref pos); } else if (char.IsDigit(c) || c == '-') { /* integer/float ? */ string s = pDigit(fmt, ref pos); if (s.IndexOf('.') < 0) { result = new ErlLong(long.Parse(s, CultureInfo.InvariantCulture)); } else { result = new ErlDouble(double.Parse(s, CultureInfo.InvariantCulture)); } } else if (c == '"') { /* string ? */ string s = pString(fmt, ref pos); result = new ErlString(s); } else if (c == '\'') { /* quoted atom ? */ string s = pQuotedAtom(fmt, ref pos); result = createAtom(s); } break; } } if (result == null) { throw new ErlException(StringConsts.ERL_INVALID_VALUE_ERROR.Args(fmt)); } return(result); }
static void Main(string[] args) { //here we handle password requests ErlTransportPasswordSource.PasswordRequired += (ps) => { Console.Write("Username: {0}\nPassword: "******"{0} ({1}): {2}", t, d, text); n.Start(); var cfg = App.ConfigRoot.NavigateSection("/erlang"); var remoteName = cfg.Children.Select(nd => nd.Name == "node" ? nd.Value : string.Empty) .FirstOrDefault(s => s.Contains("@")); Console.WriteLine("\n\nExecute the following code on remote node {0}:", remoteName); Console.WriteLine("1> F = fun F() -> receive {From, Msg} -> From ! Msg, F() end end."); Console.WriteLine("2> spawn_link(fun() -> register(me, self()), F() end).\n"); Console.WriteLine("Press any key when ready..."); Console.ReadKey(); var m = n.CreateMbox("test"); var a = new ErlAtom("hello"); var msg = new ErlTuple(m.Self, a); var remoteNode = new ErlAtom(remoteName); DateTime empty = new DateTime(2000, 1, 1, 0, 0, 0); DateTime start = empty; long count = 0; long msgs = 30000; do { var res = n.Send(m.Self, remoteNode, "me", msg); if (!res) { Console.WriteLine("Can not send message"); break; } if (start == empty) { start = DateTime.UtcNow; } var got = m.Receive(5000); if (!got.Equals((IErlObject)a)) { Console.WriteLine("Got wrong result! Expected: {0}, Got: {1}", a, got); count = -1; break; } count++; if ((count % 10000) == 0) { Console.WriteLine("Processed {0} messages", count); } //Console.ReadLine(); } while (count < msgs); var end = DateTime.UtcNow; var diff = (end - start); if (count > 0) { Console.WriteLine("Processed {0} messages. Speed: {1:F2}msgs/s, Latency: {2}us", msgs, msgs / diff.TotalSeconds, 1000.0 * diff.TotalMilliseconds / msgs); } } if (Debugger.IsAttached) { Console.ReadKey(); } }