Mercurial > pub > ImplabNet
annotate Implab/JSON/JSONWriter.cs @ 136:e9e7940c7d98 v2
shared locks + tests
author | cin |
---|---|
date | Mon, 16 Feb 2015 01:14:09 +0300 |
parents | 2573b562e328 |
children | 0fa293bb1351 |
rev | line source |
---|---|
55 | 1 using System; |
2 using System.Collections.Generic; | |
3 using System.IO; | |
4 | |
5 namespace Implab.JSON { | |
6 public class JSONWriter { | |
7 struct Context { | |
8 public bool needComma; | |
9 public JSONElementContext element; | |
10 } | |
11 Stack<Context> m_contextStack = new Stack<Context>(); | |
12 Context m_context; | |
13 | |
14 TextWriter m_writer; | |
72 | 15 readonly bool m_indent = true; |
16 readonly int m_indentSize = 4; | |
55 | 17 |
18 static readonly char [] _escapeBKS, | |
19 _escapeFWD, | |
20 _escapeCR, | |
21 _escapeNL, | |
22 _escapeTAB, | |
23 _escapeBSLASH, | |
24 _escapeQ; | |
25 | |
26 static JSONWriter() { | |
27 _escapeBKS = "\\b".ToCharArray(); | |
28 _escapeFWD = "\\f".ToCharArray(); | |
29 _escapeCR = "\\r".ToCharArray(); | |
30 _escapeNL = "\\n".ToCharArray(); | |
31 _escapeTAB = "\\t".ToCharArray(); | |
32 _escapeBSLASH = "\\\\".ToCharArray(); | |
33 _escapeQ = "\\\"".ToCharArray(); | |
34 } | |
35 | |
36 public JSONWriter(TextWriter writer) { | |
37 Safe.ArgumentNotNull(writer, "writer"); | |
38 | |
39 m_writer = writer; | |
40 } | |
41 | |
72 | 42 public JSONWriter(TextWriter writer, bool indent) { |
43 Safe.ArgumentNotNull(writer, "writer"); | |
44 | |
45 m_writer = writer; | |
46 m_indent = indent; | |
47 } | |
48 | |
49 void WriteIndent() { | |
50 if (m_indent) { | |
51 var indent = new char[m_contextStack.Count * m_indentSize + 1]; | |
52 indent[0] = '\n'; | |
53 for (int i = 1; i < indent.Length; i++) | |
54 indent[i] = ' '; | |
55 m_writer.Write(new String(indent)); | |
56 } else { | |
57 m_writer.Write(' '); | |
58 } | |
59 } | |
60 | |
55 | 61 void WriteMemberName(string name) { |
62 Safe.ArgumentNotEmpty(name, "name"); | |
63 if (m_context.element != JSONElementContext.Object) | |
64 OperationNotApplicable("WriteMember"); | |
65 if (m_context.needComma) | |
72 | 66 m_writer.Write(","); |
67 | |
68 WriteIndent(); | |
55 | 69 m_context.needComma = true; |
70 Write(name); | |
71 m_writer.Write(" : "); | |
72 } | |
73 | |
74 public void WriteValue(string name, string value) { | |
75 WriteMemberName(name); | |
76 Write(value); | |
77 } | |
78 | |
79 public void WriteValue(string name, bool value) { | |
80 WriteMemberName(name); | |
81 Write(value); | |
82 } | |
83 | |
84 public void WriteValue(string name, double value) { | |
85 WriteMemberName(name); | |
86 Write(value); | |
87 } | |
88 | |
89 public void WriteValue(string value) { | |
90 if (m_context.element != JSONElementContext.Array) | |
91 OperationNotApplicable("WriteValue"); | |
92 if (m_context.needComma) | |
72 | 93 m_writer.Write(","); |
94 WriteIndent(); | |
55 | 95 m_context.needComma = true; |
96 | |
97 Write(value); | |
98 } | |
99 | |
100 public void WriteValue(bool value) { | |
101 if (m_context.element != JSONElementContext.Array) | |
102 OperationNotApplicable("WriteValue"); | |
103 if (m_context.needComma) | |
72 | 104 m_writer.Write(","); |
55 | 105 m_context.needComma = true; |
106 | |
72 | 107 WriteIndent(); |
55 | 108 Write(value); |
109 } | |
110 | |
111 public void WriteValue(double value) { | |
112 if (m_context.element != JSONElementContext.Array) | |
113 OperationNotApplicable("WriteValue"); | |
114 if (m_context.needComma) | |
72 | 115 m_writer.Write(","); |
55 | 116 m_context.needComma = true; |
117 | |
72 | 118 WriteIndent(); |
55 | 119 Write(value); |
120 } | |
121 | |
122 public void BeginObject() { | |
123 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array) | |
124 OperationNotApplicable("BeginObject"); | |
125 if (m_context.needComma) | |
72 | 126 m_writer.Write(","); |
127 | |
128 WriteIndent(); | |
129 | |
55 | 130 m_context.needComma = true; |
131 | |
132 m_contextStack.Push(m_context); | |
133 | |
134 m_context = new Context { element = JSONElementContext.Object, needComma = false }; | |
72 | 135 m_writer.Write("{"); |
55 | 136 } |
137 | |
138 public void BeginObject(string name) { | |
139 WriteMemberName(name); | |
140 | |
141 m_contextStack.Push(m_context); | |
142 | |
143 m_context = new Context { element = JSONElementContext.Object, needComma = false }; | |
72 | 144 m_writer.Write("{"); |
55 | 145 } |
146 | |
147 public void EndObject() { | |
148 if (m_context.element != JSONElementContext.Object) | |
149 OperationNotApplicable("EndArray"); | |
72 | 150 |
55 | 151 m_context = m_contextStack.Pop(); |
72 | 152 WriteIndent(); |
153 m_writer.Write("}"); | |
55 | 154 } |
155 | |
156 public void BeginArray() { | |
157 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array) | |
158 throw new InvalidOperationException(); | |
72 | 159 if (m_context.needComma) { |
160 m_writer.Write(","); | |
161 | |
162 } | |
55 | 163 m_context.needComma = true; |
164 | |
72 | 165 WriteIndent(); |
55 | 166 m_contextStack.Push(m_context); |
167 m_context = new Context { element = JSONElementContext.Array, needComma = false }; | |
72 | 168 m_writer.Write("["); |
55 | 169 } |
170 | |
171 public void BeginArray(string name) { | |
172 WriteMemberName(name); | |
173 | |
174 m_contextStack.Push(m_context); | |
175 | |
176 m_context = new Context { element = JSONElementContext.Array, needComma = false }; | |
72 | 177 m_writer.Write("["); |
55 | 178 } |
179 | |
180 public void EndArray() { | |
181 if (m_context.element != JSONElementContext.Array) | |
182 OperationNotApplicable("EndArray"); | |
183 | |
184 m_context = m_contextStack.Pop(); | |
72 | 185 WriteIndent(); |
186 m_writer.Write("]"); | |
55 | 187 } |
188 | |
189 void Write(bool value) { | |
190 m_writer.Write(value ? "true" : "false"); | |
191 } | |
192 | |
193 | |
194 void Write(string value) { | |
115 | 195 if (value == null) { |
55 | 196 m_writer.Write("null"); |
115 | 197 return; |
198 } | |
55 | 199 |
200 var chars = value.ToCharArray(); | |
201 m_writer.Write('"'); | |
202 | |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
118
diff
changeset
|
203 // Analysis disable once ForCanBeConvertedToForeach |
55 | 204 for (int i = 0; i < chars.Length; i++) { |
205 var ch = chars[i]; | |
206 | |
207 switch (ch) { | |
208 case '\b': | |
209 m_writer.Write(_escapeBKS); | |
210 break; | |
211 case '\f': | |
212 m_writer.Write(_escapeFWD); | |
213 break; | |
214 case '\r': | |
215 m_writer.Write(_escapeCR); | |
216 break; | |
217 case '\n': | |
218 m_writer.Write(_escapeNL); | |
219 break; | |
220 case '\t': | |
221 m_writer.Write(_escapeTAB); | |
222 break; | |
223 case '\\': | |
224 m_writer.Write(_escapeBSLASH); | |
225 break; | |
226 case '"': | |
227 m_writer.Write(_escapeQ); | |
228 break; | |
229 default: | |
230 if (ch < 0x20) { | |
231 m_writer.Write("\\u00{0:x2}",(int)ch); | |
232 } else { | |
233 m_writer.Write(ch); | |
234 } | |
235 break; | |
236 } | |
237 } | |
238 | |
239 m_writer.Write('"'); | |
240 } | |
241 | |
242 void Write(double value) { | |
243 m_writer.Write(value); | |
244 } | |
245 | |
246 void OperationNotApplicable(string opName) { | |
247 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element )); | |
248 } | |
249 | |
250 } | |
251 } |